Просмотр исходного кода

remove request id param from sendSNAC

copy request id from input SNAC to output SNAC in the handler
functions instead
Mike 2 лет назад
Родитель
Сommit
c2f95541e9
49 измененных файлов с 1288 добавлено и 1137 удалено
  1. 5 5
      handler/auth.go
  2. 2 1
      handler/buddy.go
  3. 13 12
      handler/chat.go
  4. 14 11
      handler/chat_nav.go
  5. 6 2
      handler/chat_nav_test.go
  6. 1 1
      handler/chat_session_manager_mock.go
  7. 34 22
      handler/chat_test.go
  8. 26 18
      handler/feedbag.go
  9. 1 1
      handler/feedbag_manager_mock.go
  10. 116 46
      handler/feedbag_test.go
  11. 32 24
      handler/icbm.go
  12. 142 67
      handler/icbm_test.go
  13. 16 11
      handler/locate.go
  14. 62 23
      handler/locate_test.go
  15. 23 18
      handler/oservice.go
  16. 39 22
      handler/oservice_test.go
  17. 1 1
      handler/profile_manager_mock.go
  18. 1 1
      handler/session_manager_mock.go
  19. 1 1
      handler/user_manager_manager_mock.go
  20. 1 1
      oscar/snacs.go
  21. 1 1
      oscar/snacs_string.go
  22. 3 3
      server/alert.go
  23. 10 10
      server/auth_service.go
  24. 14 14
      server/bos_service.go
  25. 6 6
      server/buddy.go
  26. 12 11
      server/buddy_mock.go
  27. 0 128
      server/buddy_test.go
  28. 8 8
      server/chat.go
  29. 17 16
      server/chat_mock.go
  30. 19 19
      server/chat_nav.go
  31. 44 41
      server/chat_nav_mock.go
  32. 3 3
      server/chat_nav_test.go
  33. 9 9
      server/chat_service.go
  34. 1 1
      server/chat_test.go
  35. 7 8
      server/connection.go
  36. 43 43
      server/feedbag.go
  37. 103 96
      server/feedbag_mock.go
  38. 7 7
      server/feedbag_test.go
  39. 30 30
      server/icbm.go
  40. 57 53
      server/icbm_mock.go
  41. 4 4
      server/icbm_test.go
  42. 30 30
      server/locate.go
  43. 47 44
      server/locate_mock.go
  44. 3 3
      server/locate_test.go
  45. 56 56
      server/oservice.go
  46. 83 78
      server/oservice_bos_mock.go
  47. 67 63
      server/oservice_chat_mock.go
  48. 59 55
      server/oservice_mock.go
  49. 9 9
      server/oservice_test.go

+ 5 - 5
handler/auth.go

@@ -142,8 +142,8 @@ func (s AuthService) VerifyChatLogin(rw io.ReadWriter) (*server.ChatCookie, uint
 	return &cookie, seq, err
 	return &cookie, seq, err
 }
 }
 
 
-func (s AuthService) ReceiveAndSendAuthChallenge(snacPayloadIn oscar.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (oscar.SNACMessage, error) {
-	screenName, exists := snacPayloadIn.GetString(oscar.TLVScreenName)
+func (s AuthService) ReceiveAndSendAuthChallenge(bodyIn oscar.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (oscar.SNACMessage, error) {
+	screenName, exists := bodyIn.GetString(oscar.TLVScreenName)
 	if !exists {
 	if !exists {
 		return oscar.SNACMessage{}, errors.New("screen name doesn't exist in tlv")
 		return oscar.SNACMessage{}, errors.New("screen name doesn't exist in tlv")
 	}
 	}
@@ -185,13 +185,13 @@ func (s AuthService) ReceiveAndSendAuthChallenge(snacPayloadIn oscar.SNAC_0x17_0
 	}, nil
 	}, nil
 }
 }
 
 
-func (s AuthService) ReceiveAndSendBUCPLoginRequest(snacPayloadIn oscar.SNAC_0x17_0x02_BUCPLoginRequest, newUUID func() uuid.UUID) (oscar.SNACMessage, error) {
+func (s AuthService) ReceiveAndSendBUCPLoginRequest(bodyIn oscar.SNAC_0x17_0x02_BUCPLoginRequest, newUUID func() uuid.UUID) (oscar.SNACMessage, error) {
 
 
-	screenName, found := snacPayloadIn.GetString(oscar.TLVScreenName)
+	screenName, found := bodyIn.GetString(oscar.TLVScreenName)
 	if !found {
 	if !found {
 		return oscar.SNACMessage{}, errors.New("screen name doesn't exist in tlv")
 		return oscar.SNACMessage{}, errors.New("screen name doesn't exist in tlv")
 	}
 	}
-	md5Hash, found := snacPayloadIn.GetSlice(oscar.TLVPasswordHash)
+	md5Hash, found := bodyIn.GetSlice(oscar.TLVPasswordHash)
 	if !found {
 	if !found {
 		return oscar.SNACMessage{}, errors.New("password hash doesn't exist in tlv")
 		return oscar.SNACMessage{}, errors.New("password hash doesn't exist in tlv")
 	}
 	}

+ 2 - 1
handler/buddy.go

@@ -14,11 +14,12 @@ func NewBuddyService() *BuddyService {
 type BuddyService struct {
 type BuddyService struct {
 }
 }
 
 
-func (s BuddyService) RightsQueryHandler(context.Context) oscar.SNACMessage {
+func (s BuddyService) RightsQueryHandler(_ context.Context, frameIn oscar.SNACFrame) oscar.SNACMessage {
 	return oscar.SNACMessage{
 	return oscar.SNACMessage{
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.Buddy,
 			FoodGroup: oscar.Buddy,
 			SubGroup:  oscar.BuddyRightsReply,
 			SubGroup:  oscar.BuddyRightsReply,
+			RequestID: frameIn.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x03_0x03_BuddyRightsReply{
 		Body: oscar.SNAC_0x03_0x03_BuddyRightsReply{
 			TLVRestBlock: oscar.TLVRestBlock{
 			TLVRestBlock: oscar.TLVRestBlock{

+ 13 - 12
handler/chat.go

@@ -17,19 +17,19 @@ type ChatService struct {
 	chatRegistry *state.ChatRegistry
 	chatRegistry *state.ChatRegistry
 }
 }
 
 
-func (s ChatService) ChannelMsgToHostHandler(ctx context.Context, sess *state.Session, chatID string, snacPayloadIn oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) (*oscar.SNACMessage, error) {
-	snacFrameOut := oscar.SNACFrame{
+func (s ChatService) ChannelMsgToHostHandler(ctx context.Context, sess *state.Session, chatID string, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) (*oscar.SNACMessage, error) {
+	frameOut := oscar.SNACFrame{
 		FoodGroup: oscar.Chat,
 		FoodGroup: oscar.Chat,
 		SubGroup:  oscar.ChatChannelMsgToClient,
 		SubGroup:  oscar.ChatChannelMsgToClient,
 	}
 	}
-	snacPayloadOut := oscar.SNAC_0x0E_0x06_ChatChannelMsgToClient{
-		Cookie:  snacPayloadIn.Cookie,
-		Channel: snacPayloadIn.Channel,
+	bodyOut := oscar.SNAC_0x0E_0x06_ChatChannelMsgToClient{
+		Cookie:  inBody.Cookie,
+		Channel: inBody.Channel,
 		TLVRestBlock: oscar.TLVRestBlock{
 		TLVRestBlock: oscar.TLVRestBlock{
-			TLVList: snacPayloadIn.TLVList,
+			TLVList: inBody.TLVList,
 		},
 		},
 	}
 	}
-	snacPayloadOut.AddTLV(
+	bodyOut.AddTLV(
 		oscar.NewTLV(oscar.ChatTLVSenderInformation, oscar.TLVUserInfo{
 		oscar.NewTLV(oscar.ChatTLVSenderInformation, oscar.TLVUserInfo{
 			ScreenName:   sess.ScreenName(),
 			ScreenName:   sess.ScreenName(),
 			WarningLevel: sess.Warning(),
 			WarningLevel: sess.Warning(),
@@ -46,17 +46,18 @@ func (s ChatService) ChannelMsgToHostHandler(ctx context.Context, sess *state.Se
 
 
 	// send message to all the participants except sender
 	// send message to all the participants except sender
 	chatSessMgr.(ChatSessionManager).BroadcastExcept(ctx, sess, oscar.SNACMessage{
 	chatSessMgr.(ChatSessionManager).BroadcastExcept(ctx, sess, oscar.SNACMessage{
-		Frame: snacFrameOut,
-		Body:  snacPayloadOut,
+		Frame: frameOut,
+		Body:  bodyOut,
 	})
 	})
 
 
 	var ret *oscar.SNACMessage
 	var ret *oscar.SNACMessage
-	if _, ackMsg := snacPayloadIn.GetTLV(oscar.ChatTLVEnableReflectionFlag); ackMsg {
+	if _, ackMsg := inBody.GetTLV(oscar.ChatTLVEnableReflectionFlag); ackMsg {
 		// reflect the message back to the sender
 		// reflect the message back to the sender
 		ret = &oscar.SNACMessage{
 		ret = &oscar.SNACMessage{
-			Frame: snacFrameOut,
-			Body:  snacPayloadOut,
+			Frame: frameOut,
+			Body:  bodyOut,
 		}
 		}
+		ret.Frame.RequestID = inFrame.RequestID
 	}
 	}
 
 
 	return ret, nil
 	return ret, nil

+ 14 - 11
handler/chat_nav.go

@@ -34,11 +34,12 @@ type ChatNavService struct {
 	newChatSessMgr func() ChatSessionManager
 	newChatSessMgr func() ChatSessionManager
 }
 }
 
 
-func (s ChatNavService) RequestChatRightsHandler(context.Context) oscar.SNACMessage {
+func (s ChatNavService) RequestChatRightsHandler(_ context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
 	return oscar.SNACMessage{
 	return oscar.SNACMessage{
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.ChatNav,
 			FoodGroup: oscar.ChatNav,
 			SubGroup:  oscar.ChatNavNavInfo,
 			SubGroup:  oscar.ChatNavNavInfo,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
 		Body: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
 			TLVRestBlock: oscar.TLVRestBlock{
 			TLVRestBlock: oscar.TLVRestBlock{
@@ -65,16 +66,16 @@ func (s ChatNavService) RequestChatRightsHandler(context.Context) oscar.SNACMess
 	}
 	}
 }
 }
 
 
-func (s ChatNavService) CreateRoomHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (oscar.SNACMessage, error) {
-	name, hasName := snacPayloadIn.GetString(oscar.ChatTLVRoomName)
+func (s ChatNavService) CreateRoomHandler(_ context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (oscar.SNACMessage, error) {
+	name, hasName := inBody.GetString(oscar.ChatTLVRoomName)
 	if !hasName {
 	if !hasName {
 		return oscar.SNACMessage{}, errors.New("unable to find chat name")
 		return oscar.SNACMessage{}, errors.New("unable to find chat name")
 	}
 	}
 
 
 	room := s.newChatRoom()
 	room := s.newChatRoom()
-	room.DetailLevel = snacPayloadIn.DetailLevel
-	room.Exchange = snacPayloadIn.Exchange
-	room.InstanceNumber = snacPayloadIn.InstanceNumber
+	room.DetailLevel = inBody.DetailLevel
+	room.Exchange = inBody.Exchange
+	room.InstanceNumber = inBody.InstanceNumber
 	room.Name = name
 	room.Name = name
 
 
 	chatSessMgr := s.newChatSessMgr()
 	chatSessMgr := s.newChatSessMgr()
@@ -88,15 +89,16 @@ func (s ChatNavService) CreateRoomHandler(ctx context.Context, sess *state.Sessi
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.ChatNav,
 			FoodGroup: oscar.ChatNav,
 			SubGroup:  oscar.ChatNavNavInfo,
 			SubGroup:  oscar.ChatNavNavInfo,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
 		Body: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
 			TLVRestBlock: oscar.TLVRestBlock{
 			TLVRestBlock: oscar.TLVRestBlock{
 				TLVList: oscar.TLVList{
 				TLVList: oscar.TLVList{
 					oscar.NewTLV(oscar.ChatNavTLVRoomInfo, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
 					oscar.NewTLV(oscar.ChatNavTLVRoomInfo, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
-						Exchange:       snacPayloadIn.Exchange,
+						Exchange:       inBody.Exchange,
 						Cookie:         room.Cookie,
 						Cookie:         room.Cookie,
-						InstanceNumber: snacPayloadIn.InstanceNumber,
-						DetailLevel:    snacPayloadIn.DetailLevel,
+						InstanceNumber: inBody.InstanceNumber,
+						DetailLevel:    inBody.DetailLevel,
 						TLVBlock: oscar.TLVBlock{
 						TLVBlock: oscar.TLVBlock{
 							TLVList: room.TLVList(),
 							TLVList: room.TLVList(),
 						},
 						},
@@ -107,8 +109,8 @@ func (s ChatNavService) CreateRoomHandler(ctx context.Context, sess *state.Sessi
 	}, nil
 	}, nil
 }
 }
 
 
-func (s ChatNavService) RequestRoomInfoHandler(_ context.Context, snacPayloadIn oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (oscar.SNACMessage, error) {
-	room, _, err := s.chatRegistry.Retrieve(string(snacPayloadIn.Cookie))
+func (s ChatNavService) RequestRoomInfoHandler(_ context.Context, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (oscar.SNACMessage, error) {
+	room, _, err := s.chatRegistry.Retrieve(string(inBody.Cookie))
 	if err != nil {
 	if err != nil {
 		return oscar.SNACMessage{}, err
 		return oscar.SNACMessage{}, err
 	}
 	}
@@ -117,6 +119,7 @@ func (s ChatNavService) RequestRoomInfoHandler(_ context.Context, snacPayloadIn
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.ChatNav,
 			FoodGroup: oscar.ChatNav,
 			SubGroup:  oscar.ChatNavNavInfo,
 			SubGroup:  oscar.ChatNavNavInfo,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
 		Body: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
 			TLVRestBlock: oscar.TLVRestBlock{
 			TLVRestBlock: oscar.TLVRestBlock{

+ 6 - 2
handler/chat_nav_test.go

@@ -25,7 +25,10 @@ func TestSendAndReceiveCreateRoom(t *testing.T) {
 	//
 	//
 	// send input SNAC
 	// send input SNAC
 	//
 	//
-	inputSNAC := oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
+	inFrame := oscar.SNACFrame{
+		RequestID: 1234,
+	}
+	inBody := oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
 		Exchange:       1,
 		Exchange:       1,
 		Cookie:         "create", // actual canned value sent by AIM client
 		Cookie:         "create", // actual canned value sent by AIM client
 		InstanceNumber: 2,
 		InstanceNumber: 2,
@@ -48,7 +51,7 @@ func TestSendAndReceiveCreateRoom(t *testing.T) {
 			return sm
 			return sm
 		},
 		},
 	}
 	}
-	outputSNAC, err := svc.CreateRoomHandler(context.Background(), userSess, inputSNAC)
+	outputSNAC, err := svc.CreateRoomHandler(context.Background(), userSess, inFrame, inBody)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
 	//
 	//
@@ -73,6 +76,7 @@ func TestSendAndReceiveCreateRoom(t *testing.T) {
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.ChatNav,
 			FoodGroup: oscar.ChatNav,
 			SubGroup:  oscar.ChatNavNavInfo,
 			SubGroup:  oscar.ChatNavNavInfo,
+			RequestID: 1234,
 		},
 		},
 		Body: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
 		Body: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
 			TLVRestBlock: oscar.TLVRestBlock{
 			TLVRestBlock: oscar.TLVRestBlock{

+ 1 - 1
handler/chat_session_manager_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package handler
 package handler
 
 

+ 34 - 22
handler/chat_test.go

@@ -17,7 +17,7 @@ func TestSendAndReceiveChatChannelMsgToHost(t *testing.T) {
 		// userSession is the session of the user sending the chat message
 		// userSession is the session of the user sending the chat message
 		userSession *state.Session
 		userSession *state.Session
 		// inputSNAC is the SNAC sent by the sender client
 		// inputSNAC is the SNAC sent by the sender client
-		inputSNAC oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost
+		inputSNAC oscar.SNACMessage
 		// expectSNACToParticipants is the message the server broadcast to chat
 		// expectSNACToParticipants is the message the server broadcast to chat
 		// room participants (except the sender)
 		// room participants (except the sender)
 		expectSNACToParticipants oscar.SNACMessage
 		expectSNACToParticipants oscar.SNACMessage
@@ -26,18 +26,23 @@ func TestSendAndReceiveChatChannelMsgToHost(t *testing.T) {
 		{
 		{
 			name:        "send chat room message, expect acknowledgement to sender client",
 			name:        "send chat room message, expect acknowledgement to sender client",
 			userSession: newTestSession("user_sending_chat_msg", sessOptCannedSignonTime),
 			userSession: newTestSession("user_sending_chat_msg", sessOptCannedSignonTime),
-			inputSNAC: oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost{
-				Cookie:  1234,
-				Channel: 14,
-				TLVRestBlock: oscar.TLVRestBlock{
-					TLVList: oscar.TLVList{
-						{
-							TType: oscar.ChatTLVPublicWhisperFlag,
-							Val:   []byte{},
-						},
-						{
-							TType: oscar.ChatTLVEnableReflectionFlag,
-							Val:   []byte{},
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost{
+					Cookie:  1234,
+					Channel: 14,
+					TLVRestBlock: oscar.TLVRestBlock{
+						TLVList: oscar.TLVList{
+							{
+								TType: oscar.ChatTLVPublicWhisperFlag,
+								Val:   []byte{},
+							},
+							{
+								TType: oscar.ChatTLVEnableReflectionFlag,
+								Val:   []byte{},
+							},
 						},
 						},
 					},
 					},
 				},
 				},
@@ -64,6 +69,7 @@ func TestSendAndReceiveChatChannelMsgToHost(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Chat,
 					FoodGroup: oscar.Chat,
 					SubGroup:  oscar.ChatChannelMsgToClient,
 					SubGroup:  oscar.ChatChannelMsgToClient,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x0E_0x06_ChatChannelMsgToClient{
 				Body: oscar.SNAC_0x0E_0x06_ChatChannelMsgToClient{
 					Cookie:  1234,
 					Cookie:  1234,
@@ -81,14 +87,19 @@ func TestSendAndReceiveChatChannelMsgToHost(t *testing.T) {
 		{
 		{
 			name:        "send chat room message, don't expect acknowledgement to sender client",
 			name:        "send chat room message, don't expect acknowledgement to sender client",
 			userSession: newTestSession("user_sending_chat_msg", sessOptCannedSignonTime),
 			userSession: newTestSession("user_sending_chat_msg", sessOptCannedSignonTime),
-			inputSNAC: oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost{
-				Cookie:  1234,
-				Channel: 14,
-				TLVRestBlock: oscar.TLVRestBlock{
-					TLVList: oscar.TLVList{
-						{
-							TType: oscar.ChatTLVPublicWhisperFlag,
-							Val:   []byte{},
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost{
+					Cookie:  1234,
+					Channel: 14,
+					TLVRestBlock: oscar.TLVRestBlock{
+						TLVList: oscar.TLVList{
+							{
+								TType: oscar.ChatTLVPublicWhisperFlag,
+								Val:   []byte{},
+							},
 						},
 						},
 					},
 					},
 				},
 				},
@@ -127,7 +138,8 @@ func TestSendAndReceiveChatChannelMsgToHost(t *testing.T) {
 			}
 			}
 			svc.chatRegistry.Register(state.ChatRoom{Cookie: chatID}, chatSessMgr)
 			svc.chatRegistry.Register(state.ChatRoom{Cookie: chatID}, chatSessMgr)
 
 
-			outputSNAC, err := svc.ChannelMsgToHostHandler(context.Background(), tc.userSession, chatID, tc.inputSNAC)
+			outputSNAC, err := svc.ChannelMsgToHostHandler(context.Background(), tc.userSession, chatID,
+				tc.inputSNAC.Frame, tc.inputSNAC.Body.(oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost))
 			assert.NoError(t, err)
 			assert.NoError(t, err)
 
 
 			if tc.expectOutput.Frame == (oscar.SNACFrame{}) {
 			if tc.expectOutput.Frame == (oscar.SNACFrame{}) {

+ 26 - 18
handler/feedbag.go

@@ -17,11 +17,12 @@ type FeedbagService struct {
 	feedbagManager FeedbagManager
 	feedbagManager FeedbagManager
 }
 }
 
 
-func (s FeedbagService) RightsQueryHandler(context.Context) oscar.SNACMessage {
+func (s FeedbagService) RightsQueryHandler(_ context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
 	return oscar.SNACMessage{
 	return oscar.SNACMessage{
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.Feedbag,
 			FoodGroup: oscar.Feedbag,
 			SubGroup:  oscar.FeedbagRightsReply,
 			SubGroup:  oscar.FeedbagRightsReply,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x13_0x03_FeedbagRightsReply{
 		Body: oscar.SNAC_0x13_0x03_FeedbagRightsReply{
 			TLVRestBlock: oscar.TLVRestBlock{
 			TLVRestBlock: oscar.TLVRestBlock{
@@ -65,7 +66,7 @@ func (s FeedbagService) RightsQueryHandler(context.Context) oscar.SNACMessage {
 	}
 	}
 }
 }
 
 
-func (s FeedbagService) QueryHandler(_ context.Context, sess *state.Session) (oscar.SNACMessage, error) {
+func (s FeedbagService) QueryHandler(_ context.Context, sess *state.Session, inFrame oscar.SNACFrame) (oscar.SNACMessage, error) {
 	fb, err := s.feedbagManager.Retrieve(sess.ScreenName())
 	fb, err := s.feedbagManager.Retrieve(sess.ScreenName())
 	if err != nil {
 	if err != nil {
 		return oscar.SNACMessage{}, err
 		return oscar.SNACMessage{}, err
@@ -84,6 +85,7 @@ func (s FeedbagService) QueryHandler(_ context.Context, sess *state.Session) (os
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.Feedbag,
 			FoodGroup: oscar.Feedbag,
 			SubGroup:  oscar.FeedbagReply,
 			SubGroup:  oscar.FeedbagReply,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x13_0x06_FeedbagReply{
 		Body: oscar.SNAC_0x13_0x06_FeedbagReply{
 			Version:    0,
 			Version:    0,
@@ -93,7 +95,7 @@ func (s FeedbagService) QueryHandler(_ context.Context, sess *state.Session) (os
 	}, nil
 	}, nil
 }
 }
 
 
-func (s FeedbagService) QueryIfModifiedHandler(_ context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) (oscar.SNACMessage, error) {
+func (s FeedbagService) QueryIfModifiedHandler(_ context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) (oscar.SNACMessage, error) {
 	fb, err := s.feedbagManager.Retrieve(sess.ScreenName())
 	fb, err := s.feedbagManager.Retrieve(sess.ScreenName())
 	if err != nil {
 	if err != nil {
 		return oscar.SNACMessage{}, err
 		return oscar.SNACMessage{}, err
@@ -106,11 +108,12 @@ func (s FeedbagService) QueryIfModifiedHandler(_ context.Context, sess *state.Se
 		if err != nil {
 		if err != nil {
 			return oscar.SNACMessage{}, err
 			return oscar.SNACMessage{}, err
 		}
 		}
-		if lm.Before(time.Unix(int64(snacPayloadIn.LastUpdate), 0)) {
+		if lm.Before(time.Unix(int64(inBody.LastUpdate), 0)) {
 			return oscar.SNACMessage{
 			return oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Feedbag,
 					FoodGroup: oscar.Feedbag,
 					SubGroup:  oscar.FeedbagReplyNotModified,
 					SubGroup:  oscar.FeedbagReplyNotModified,
+					RequestID: inFrame.RequestID,
 				},
 				},
 				Body: oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{
 				Body: oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{
 					LastUpdate: uint32(lm.Unix()),
 					LastUpdate: uint32(lm.Unix()),
@@ -124,6 +127,7 @@ func (s FeedbagService) QueryIfModifiedHandler(_ context.Context, sess *state.Se
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.Feedbag,
 			FoodGroup: oscar.Feedbag,
 			SubGroup:  oscar.FeedbagReply,
 			SubGroup:  oscar.FeedbagReply,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x13_0x06_FeedbagReply{
 		Body: oscar.SNAC_0x13_0x06_FeedbagReply{
 			Version:    0,
 			Version:    0,
@@ -133,8 +137,8 @@ func (s FeedbagService) QueryIfModifiedHandler(_ context.Context, sess *state.Se
 	}, nil
 	}, nil
 }
 }
 
 
-func (s FeedbagService) InsertItemHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x08_FeedbagInsertItem) (oscar.SNACMessage, error) {
-	for _, item := range snacPayloadIn.Items {
+func (s FeedbagService) InsertItemHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x08_FeedbagInsertItem) (oscar.SNACMessage, error) {
+	for _, item := range inBody.Items {
 		// don't let users block themselves, it causes the AIM client to go
 		// don't let users block themselves, it causes the AIM client to go
 		// into a weird state.
 		// into a weird state.
 		if item.ClassID == 3 && item.Name == sess.ScreenName() {
 		if item.ClassID == 3 && item.Name == sess.ScreenName() {
@@ -142,6 +146,7 @@ func (s FeedbagService) InsertItemHandler(ctx context.Context, sess *state.Sessi
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Feedbag,
 					FoodGroup: oscar.Feedbag,
 					SubGroup:  oscar.FeedbagErr,
 					SubGroup:  oscar.FeedbagErr,
+					RequestID: inFrame.RequestID,
 				},
 				},
 				Body: oscar.SNACError{
 				Body: oscar.SNACError{
 					Code: oscar.ErrorCodeNotSupportedByHost,
 					Code: oscar.ErrorCodeNotSupportedByHost,
@@ -150,11 +155,11 @@ func (s FeedbagService) InsertItemHandler(ctx context.Context, sess *state.Sessi
 		}
 		}
 	}
 	}
 
 
-	if err := s.feedbagManager.Upsert(sess.ScreenName(), snacPayloadIn.Items); err != nil {
+	if err := s.feedbagManager.Upsert(sess.ScreenName(), inBody.Items); err != nil {
 		return oscar.SNACMessage{}, nil
 		return oscar.SNACMessage{}, nil
 	}
 	}
 
 
-	for _, item := range snacPayloadIn.Items {
+	for _, item := range inBody.Items {
 		switch item.ClassID {
 		switch item.ClassID {
 		case oscar.FeedbagClassIdBuddy, oscar.FeedbagClassIDPermit: // add new buddy
 		case oscar.FeedbagClassIdBuddy, oscar.FeedbagClassIDPermit: // add new buddy
 			unicastArrival(ctx, item.Name, sess.ScreenName(), s.sessionManager)
 			unicastArrival(ctx, item.Name, sess.ScreenName(), s.sessionManager)
@@ -167,7 +172,7 @@ func (s FeedbagService) InsertItemHandler(ctx context.Context, sess *state.Sessi
 	}
 	}
 
 
 	snacPayloadOut := oscar.SNAC_0x13_0x0E_FeedbagStatus{}
 	snacPayloadOut := oscar.SNAC_0x13_0x0E_FeedbagStatus{}
-	for range snacPayloadIn.Items {
+	for range inBody.Items {
 		snacPayloadOut.Results = append(snacPayloadOut.Results, 0x0000)
 		snacPayloadOut.Results = append(snacPayloadOut.Results, 0x0000)
 	}
 	}
 
 
@@ -175,17 +180,18 @@ func (s FeedbagService) InsertItemHandler(ctx context.Context, sess *state.Sessi
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.Feedbag,
 			FoodGroup: oscar.Feedbag,
 			SubGroup:  oscar.FeedbagStatus,
 			SubGroup:  oscar.FeedbagStatus,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: snacPayloadOut,
 		Body: snacPayloadOut,
 	}, nil
 	}, nil
 }
 }
 
 
-func (s FeedbagService) UpdateItemHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x09_FeedbagUpdateItem) (oscar.SNACMessage, error) {
-	if err := s.feedbagManager.Upsert(sess.ScreenName(), snacPayloadIn.Items); err != nil {
+func (s FeedbagService) UpdateItemHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x09_FeedbagUpdateItem) (oscar.SNACMessage, error) {
+	if err := s.feedbagManager.Upsert(sess.ScreenName(), inBody.Items); err != nil {
 		return oscar.SNACMessage{}, nil
 		return oscar.SNACMessage{}, nil
 	}
 	}
 
 
-	for _, item := range snacPayloadIn.Items {
+	for _, item := range inBody.Items {
 		switch item.ClassID {
 		switch item.ClassID {
 		case oscar.FeedbagClassIdBuddy, oscar.FeedbagClassIDPermit:
 		case oscar.FeedbagClassIdBuddy, oscar.FeedbagClassIDPermit:
 			unicastArrival(ctx, item.Name, sess.ScreenName(), s.sessionManager)
 			unicastArrival(ctx, item.Name, sess.ScreenName(), s.sessionManager)
@@ -193,7 +199,7 @@ func (s FeedbagService) UpdateItemHandler(ctx context.Context, sess *state.Sessi
 	}
 	}
 
 
 	snacPayloadOut := oscar.SNAC_0x13_0x0E_FeedbagStatus{}
 	snacPayloadOut := oscar.SNAC_0x13_0x0E_FeedbagStatus{}
-	for range snacPayloadIn.Items {
+	for range inBody.Items {
 		snacPayloadOut.Results = append(snacPayloadOut.Results, 0x0000)
 		snacPayloadOut.Results = append(snacPayloadOut.Results, 0x0000)
 	}
 	}
 
 
@@ -201,17 +207,18 @@ func (s FeedbagService) UpdateItemHandler(ctx context.Context, sess *state.Sessi
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.Feedbag,
 			FoodGroup: oscar.Feedbag,
 			SubGroup:  oscar.FeedbagStatus,
 			SubGroup:  oscar.FeedbagStatus,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: snacPayloadOut,
 		Body: snacPayloadOut,
 	}, nil
 	}, nil
 }
 }
 
 
-func (s FeedbagService) DeleteItemHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) (oscar.SNACMessage, error) {
-	if err := s.feedbagManager.Delete(sess.ScreenName(), snacPayloadIn.Items); err != nil {
+func (s FeedbagService) DeleteItemHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) (oscar.SNACMessage, error) {
+	if err := s.feedbagManager.Delete(sess.ScreenName(), inBody.Items); err != nil {
 		return oscar.SNACMessage{}, err
 		return oscar.SNACMessage{}, err
 	}
 	}
 
 
-	for _, item := range snacPayloadIn.Items {
+	for _, item := range inBody.Items {
 		if item.ClassID == oscar.FeedbagClassIDDeny {
 		if item.ClassID == oscar.FeedbagClassIDDeny {
 			unicastArrival(ctx, item.Name, sess.ScreenName(), s.sessionManager)
 			unicastArrival(ctx, item.Name, sess.ScreenName(), s.sessionManager)
 			unicastArrival(ctx, sess.ScreenName(), item.Name, s.sessionManager)
 			unicastArrival(ctx, sess.ScreenName(), item.Name, s.sessionManager)
@@ -219,7 +226,7 @@ func (s FeedbagService) DeleteItemHandler(ctx context.Context, sess *state.Sessi
 	}
 	}
 
 
 	snacPayloadOut := oscar.SNAC_0x13_0x0E_FeedbagStatus{}
 	snacPayloadOut := oscar.SNAC_0x13_0x0E_FeedbagStatus{}
-	for range snacPayloadIn.Items {
+	for range inBody.Items {
 		snacPayloadOut.Results = append(snacPayloadOut.Results, 0x0000) // success by default
 		snacPayloadOut.Results = append(snacPayloadOut.Results, 0x0000) // success by default
 	}
 	}
 
 
@@ -227,6 +234,7 @@ func (s FeedbagService) DeleteItemHandler(ctx context.Context, sess *state.Sessi
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.Feedbag,
 			FoodGroup: oscar.Feedbag,
 			SubGroup:  oscar.FeedbagStatus,
 			SubGroup:  oscar.FeedbagStatus,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: snacPayloadOut,
 		Body: snacPayloadOut,
 	}, nil
 	}, nil
@@ -234,5 +242,5 @@ func (s FeedbagService) DeleteItemHandler(ctx context.Context, sess *state.Sessi
 
 
 // StartClusterHandler exists to capture the SNAC input in unit tests to verify
 // StartClusterHandler exists to capture the SNAC input in unit tests to verify
 // it's correctly unmarshalled.
 // it's correctly unmarshalled.
-func (s FeedbagService) StartClusterHandler(context.Context, oscar.SNAC_0x13_0x11_FeedbagStartCluster) {
+func (s FeedbagService) StartClusterHandler(context.Context, oscar.SNACFrame, oscar.SNAC_0x13_0x11_FeedbagStartCluster) {
 }
 }

+ 1 - 1
handler/feedbag_manager_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package handler
 package handler
 
 

+ 116 - 46
handler/feedbag_test.go

@@ -20,6 +20,8 @@ func TestQueryHandler(t *testing.T) {
 		feedbagItems []oscar.FeedbagItem
 		feedbagItems []oscar.FeedbagItem
 		// lastModified is the time the buddy list was last changed
 		// lastModified is the time the buddy list was last changed
 		lastModified time.Time
 		lastModified time.Time
+		// inputSNAC is the SNAC sent by the sender client
+		inputSNAC oscar.SNACMessage
 		// expectOutput is the SNAC payload sent from the server to the
 		// expectOutput is the SNAC payload sent from the server to the
 		// recipient client
 		// recipient client
 		expectOutput oscar.SNACMessage
 		expectOutput oscar.SNACMessage
@@ -29,10 +31,16 @@ func TestQueryHandler(t *testing.T) {
 			screenName:   "user_screen_name",
 			screenName:   "user_screen_name",
 			feedbagItems: []oscar.FeedbagItem{},
 			feedbagItems: []oscar.FeedbagItem{},
 			lastModified: time.UnixMilli(0),
 			lastModified: time.UnixMilli(0),
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Feedbag,
 					FoodGroup: oscar.Feedbag,
 					SubGroup:  oscar.FeedbagReply,
 					SubGroup:  oscar.FeedbagReply,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x13_0x06_FeedbagReply{
 				Body: oscar.SNAC_0x13_0x06_FeedbagReply{
 					Items: []oscar.FeedbagItem{},
 					Items: []oscar.FeedbagItem{},
@@ -51,10 +59,16 @@ func TestQueryHandler(t *testing.T) {
 				},
 				},
 			},
 			},
 			lastModified: time.UnixMilli(1696472198082),
 			lastModified: time.UnixMilli(1696472198082),
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Feedbag,
 					FoodGroup: oscar.Feedbag,
 					SubGroup:  oscar.FeedbagReply,
 					SubGroup:  oscar.FeedbagReply,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x13_0x06_FeedbagReply{
 				Body: oscar.SNAC_0x13_0x06_FeedbagReply{
 					Version: 0,
 					Version: 0,
@@ -93,7 +107,7 @@ func TestQueryHandler(t *testing.T) {
 			svc := FeedbagService{
 			svc := FeedbagService{
 				feedbagManager: fm,
 				feedbagManager: fm,
 			}
 			}
-			outputSNAC, err := svc.QueryHandler(nil, senderSession)
+			outputSNAC, err := svc.QueryHandler(nil, senderSession, tc.inputSNAC.Frame)
 			assert.NoError(t, err)
 			assert.NoError(t, err)
 			assert.Equal(t, tc.expectOutput, outputSNAC)
 			assert.Equal(t, tc.expectOutput, outputSNAC)
 		})
 		})
@@ -111,7 +125,7 @@ func TestQueryIfModifiedHandler(t *testing.T) {
 		// lastModified is the time the buddy list was last changed
 		// lastModified is the time the buddy list was last changed
 		lastModified time.Time
 		lastModified time.Time
 		// inputSNAC is the SNAC sent by the sender client
 		// inputSNAC is the SNAC sent by the sender client
-		inputSNAC oscar.SNAC_0x13_0x05_FeedbagQueryIfModified
+		inputSNAC oscar.SNACMessage
 		// expectOutput is the SNAC payload sent from the server to the
 		// expectOutput is the SNAC payload sent from the server to the
 		// recipient client
 		// recipient client
 		expectOutput oscar.SNACMessage
 		expectOutput oscar.SNACMessage
@@ -121,13 +135,19 @@ func TestQueryIfModifiedHandler(t *testing.T) {
 			screenName:   "user_screen_name",
 			screenName:   "user_screen_name",
 			feedbagItems: []oscar.FeedbagItem{},
 			feedbagItems: []oscar.FeedbagItem{},
 			lastModified: time.UnixMilli(0),
 			lastModified: time.UnixMilli(0),
-			inputSNAC: oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{
-				LastUpdate: uint32(time.UnixMilli(100000).Unix()),
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{
+					LastUpdate: uint32(time.UnixMilli(100000).Unix()),
+				},
 			},
 			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Feedbag,
 					FoodGroup: oscar.Feedbag,
 					SubGroup:  oscar.FeedbagReply,
 					SubGroup:  oscar.FeedbagReply,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x13_0x06_FeedbagReply{
 				Body: oscar.SNAC_0x13_0x06_FeedbagReply{
 					Items: []oscar.FeedbagItem{},
 					Items: []oscar.FeedbagItem{},
@@ -146,13 +166,19 @@ func TestQueryIfModifiedHandler(t *testing.T) {
 				},
 				},
 			},
 			},
 			lastModified: time.UnixMilli(200000),
 			lastModified: time.UnixMilli(200000),
-			inputSNAC: oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{
-				LastUpdate: uint32(time.UnixMilli(100000).Unix()),
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{
+					LastUpdate: uint32(time.UnixMilli(100000).Unix()),
+				},
 			},
 			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Feedbag,
 					FoodGroup: oscar.Feedbag,
 					SubGroup:  oscar.FeedbagReply,
 					SubGroup:  oscar.FeedbagReply,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x13_0x06_FeedbagReply{
 				Body: oscar.SNAC_0x13_0x06_FeedbagReply{
 					Version: 0,
 					Version: 0,
@@ -180,13 +206,19 @@ func TestQueryIfModifiedHandler(t *testing.T) {
 				},
 				},
 			},
 			},
 			lastModified: time.UnixMilli(100000),
 			lastModified: time.UnixMilli(100000),
-			inputSNAC: oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{
-				LastUpdate: uint32(time.UnixMilli(200000).Unix()),
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{
+					LastUpdate: uint32(time.UnixMilli(200000).Unix()),
+				},
 			},
 			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Feedbag,
 					FoodGroup: oscar.Feedbag,
 					SubGroup:  oscar.FeedbagReplyNotModified,
 					SubGroup:  oscar.FeedbagReplyNotModified,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{
 				Body: oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{
 					LastUpdate: uint32(time.UnixMilli(100000).Unix()),
 					LastUpdate: uint32(time.UnixMilli(100000).Unix()),
@@ -217,7 +249,8 @@ func TestQueryIfModifiedHandler(t *testing.T) {
 			svc := FeedbagService{
 			svc := FeedbagService{
 				feedbagManager: fm,
 				feedbagManager: fm,
 			}
 			}
-			outputSNAC, err := svc.QueryIfModifiedHandler(nil, senderSession, tc.inputSNAC)
+			outputSNAC, err := svc.QueryIfModifiedHandler(nil, senderSession, tc.inputSNAC.Frame,
+				tc.inputSNAC.Body.(oscar.SNAC_0x13_0x05_FeedbagQueryIfModified))
 			assert.NoError(t, err)
 			assert.NoError(t, err)
 			//
 			//
 			// verify output
 			// verify output
@@ -236,7 +269,7 @@ func TestInsertItemHandler(t *testing.T) {
 		// feedbagItems is the list of items in user's buddy list
 		// feedbagItems is the list of items in user's buddy list
 		feedbagItems []oscar.FeedbagItem
 		feedbagItems []oscar.FeedbagItem
 		// inputSNAC is the SNAC sent by the sender client
 		// inputSNAC is the SNAC sent by the sender client
-		inputSNAC oscar.SNAC_0x13_0x08_FeedbagInsertItem
+		inputSNAC oscar.SNACMessage
 		// screenNameLookups is the list of user's online buddies
 		// screenNameLookups is the list of user's online buddies
 		screenNameLookups map[string]struct {
 		screenNameLookups map[string]struct {
 			sess *state.Session
 			sess *state.Session
@@ -253,15 +286,20 @@ func TestInsertItemHandler(t *testing.T) {
 		{
 		{
 			name:        "user adds 2 online buddies, expect OK response",
 			name:        "user adds 2 online buddies, expect OK response",
 			userSession: newTestSession("user_screen_name"),
 			userSession: newTestSession("user_screen_name"),
-			inputSNAC: oscar.SNAC_0x13_0x08_FeedbagInsertItem{
-				Items: []oscar.FeedbagItem{
-					{
-						ClassID: 2,
-						Name:    "buddy_1_online",
-					},
-					{
-						ClassID: 2,
-						Name:    "buddy_2_online",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x13_0x08_FeedbagInsertItem{
+					Items: []oscar.FeedbagItem{
+						{
+							ClassID: 2,
+							Name:    "buddy_1_online",
+						},
+						{
+							ClassID: 2,
+							Name:    "buddy_2_online",
+						},
 					},
 					},
 				},
 				},
 			},
 			},
@@ -283,6 +321,7 @@ func TestInsertItemHandler(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Feedbag,
 					FoodGroup: oscar.Feedbag,
 					SubGroup:  oscar.FeedbagStatus,
 					SubGroup:  oscar.FeedbagStatus,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x13_0x0E_FeedbagStatus{
 				Body: oscar.SNAC_0x13_0x0E_FeedbagStatus{
 					Results: []uint16{0x0000, 0x0000},
 					Results: []uint16{0x0000, 0x0000},
@@ -331,11 +370,16 @@ func TestInsertItemHandler(t *testing.T) {
 		{
 		{
 			name:        "user adds an offline buddy, expect OK response and 0 buddy arrived events",
 			name:        "user adds an offline buddy, expect OK response and 0 buddy arrived events",
 			userSession: newTestSession("user_screen_name"),
 			userSession: newTestSession("user_screen_name"),
-			inputSNAC: oscar.SNAC_0x13_0x08_FeedbagInsertItem{
-				Items: []oscar.FeedbagItem{
-					{
-						ClassID: 2,
-						Name:    "buddy_offline",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x13_0x08_FeedbagInsertItem{
+					Items: []oscar.FeedbagItem{
+						{
+							ClassID: 2,
+							Name:    "buddy_offline",
+						},
 					},
 					},
 				},
 				},
 			},
 			},
@@ -351,6 +395,7 @@ func TestInsertItemHandler(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Feedbag,
 					FoodGroup: oscar.Feedbag,
 					SubGroup:  oscar.FeedbagStatus,
 					SubGroup:  oscar.FeedbagStatus,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x13_0x0E_FeedbagStatus{
 				Body: oscar.SNAC_0x13_0x0E_FeedbagStatus{
 					Results: []uint16{0x0000},
 					Results: []uint16{0x0000},
@@ -360,11 +405,16 @@ func TestInsertItemHandler(t *testing.T) {
 		{
 		{
 			name:        "users adds an invisible buddy, expect OK response and 0 buddy arrived events",
 			name:        "users adds an invisible buddy, expect OK response and 0 buddy arrived events",
 			userSession: newTestSession("user_screen_name"),
 			userSession: newTestSession("user_screen_name"),
-			inputSNAC: oscar.SNAC_0x13_0x08_FeedbagInsertItem{
-				Items: []oscar.FeedbagItem{
-					{
-						ClassID: 2,
-						Name:    "invisible_buddy_online",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x13_0x08_FeedbagInsertItem{
+					Items: []oscar.FeedbagItem{
+						{
+							ClassID: 2,
+							Name:    "invisible_buddy_online",
+						},
 					},
 					},
 				},
 				},
 			},
 			},
@@ -380,6 +430,7 @@ func TestInsertItemHandler(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Feedbag,
 					FoodGroup: oscar.Feedbag,
 					SubGroup:  oscar.FeedbagStatus,
 					SubGroup:  oscar.FeedbagStatus,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x13_0x0E_FeedbagStatus{
 				Body: oscar.SNAC_0x13_0x0E_FeedbagStatus{
 					Results: []uint16{0x0000},
 					Results: []uint16{0x0000},
@@ -390,11 +441,16 @@ func TestInsertItemHandler(t *testing.T) {
 			name: "user blocks buddy currently online, expect OK response, buddy departed event client, 1 buddy " +
 			name: "user blocks buddy currently online, expect OK response, buddy departed event client, 1 buddy " +
 				"departed event sent to buddy",
 				"departed event sent to buddy",
 			userSession: newTestSession("user_screen_name"),
 			userSession: newTestSession("user_screen_name"),
-			inputSNAC: oscar.SNAC_0x13_0x08_FeedbagInsertItem{
-				Items: []oscar.FeedbagItem{
-					{
-						ClassID: 3,
-						Name:    "buddy_1",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x13_0x08_FeedbagInsertItem{
+					Items: []oscar.FeedbagItem{
+						{
+							ClassID: 3,
+							Name:    "buddy_1",
+						},
 					},
 					},
 				},
 				},
 			},
 			},
@@ -448,6 +504,7 @@ func TestInsertItemHandler(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Feedbag,
 					FoodGroup: oscar.Feedbag,
 					SubGroup:  oscar.FeedbagStatus,
 					SubGroup:  oscar.FeedbagStatus,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x13_0x0E_FeedbagStatus{
 				Body: oscar.SNAC_0x13_0x0E_FeedbagStatus{
 					Results: []uint16{0x0000},
 					Results: []uint16{0x0000},
@@ -457,11 +514,16 @@ func TestInsertItemHandler(t *testing.T) {
 		{
 		{
 			name:        "user blocks buddy currently offline, expect OK response and a superfluous buddy departed events",
 			name:        "user blocks buddy currently offline, expect OK response and a superfluous buddy departed events",
 			userSession: newTestSession("user_screen_name"),
 			userSession: newTestSession("user_screen_name"),
-			inputSNAC: oscar.SNAC_0x13_0x08_FeedbagInsertItem{
-				Items: []oscar.FeedbagItem{
-					{
-						ClassID: 3,
-						Name:    "buddy_1",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x13_0x08_FeedbagInsertItem{
+					Items: []oscar.FeedbagItem{
+						{
+							ClassID: 3,
+							Name:    "buddy_1",
+						},
 					},
 					},
 				},
 				},
 			},
 			},
@@ -480,6 +542,7 @@ func TestInsertItemHandler(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Feedbag,
 					FoodGroup: oscar.Feedbag,
 					SubGroup:  oscar.FeedbagStatus,
 					SubGroup:  oscar.FeedbagStatus,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x13_0x0E_FeedbagStatus{
 				Body: oscar.SNAC_0x13_0x0E_FeedbagStatus{
 					Results: []uint16{0x0000},
 					Results: []uint16{0x0000},
@@ -509,11 +572,16 @@ func TestInsertItemHandler(t *testing.T) {
 		{
 		{
 			name:        "user tries to block themselves, expect feedback error",
 			name:        "user tries to block themselves, expect feedback error",
 			userSession: newTestSession("user_screen_name"),
 			userSession: newTestSession("user_screen_name"),
-			inputSNAC: oscar.SNAC_0x13_0x08_FeedbagInsertItem{
-				Items: []oscar.FeedbagItem{
-					{
-						ClassID: 3,
-						Name:    "user_screen_name",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x13_0x08_FeedbagInsertItem{
+					Items: []oscar.FeedbagItem{
+						{
+							ClassID: 3,
+							Name:    "user_screen_name",
+						},
 					},
 					},
 				},
 				},
 			},
 			},
@@ -521,6 +589,7 @@ func TestInsertItemHandler(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Feedbag,
 					FoodGroup: oscar.Feedbag,
 					SubGroup:  oscar.FeedbagErr,
 					SubGroup:  oscar.FeedbagErr,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNACError{
 				Body: oscar.SNACError{
 					Code: oscar.ErrorCodeNotSupportedByHost,
 					Code: oscar.ErrorCodeNotSupportedByHost,
@@ -536,7 +605,7 @@ func TestInsertItemHandler(t *testing.T) {
 			//
 			//
 			fm := newMockFeedbagManager(t)
 			fm := newMockFeedbagManager(t)
 			fm.EXPECT().
 			fm.EXPECT().
-				Upsert(tc.userSession.ScreenName(), tc.inputSNAC.Items).
+				Upsert(tc.userSession.ScreenName(), tc.inputSNAC.Body.(oscar.SNAC_0x13_0x08_FeedbagInsertItem).Items).
 				Return(nil).
 				Return(nil).
 				Maybe()
 				Maybe()
 			fm.EXPECT().
 			fm.EXPECT().
@@ -562,7 +631,8 @@ func TestInsertItemHandler(t *testing.T) {
 				feedbagManager: fm,
 				feedbagManager: fm,
 				sessionManager: sm,
 				sessionManager: sm,
 			}
 			}
-			output, err := svc.InsertItemHandler(nil, tc.userSession, tc.inputSNAC)
+			output, err := svc.InsertItemHandler(nil, tc.userSession, tc.inputSNAC.Frame,
+				tc.inputSNAC.Body.(oscar.SNAC_0x13_0x08_FeedbagInsertItem))
 			assert.NoError(t, err)
 			assert.NoError(t, err)
 			//
 			//
 			// verify response
 			// verify response

+ 32 - 24
handler/icbm.go

@@ -21,11 +21,12 @@ type ICBMService struct {
 	feedbagManager FeedbagManager
 	feedbagManager FeedbagManager
 }
 }
 
 
-func (s ICBMService) ParameterQueryHandler(context.Context) oscar.SNACMessage {
+func (s ICBMService) ParameterQueryHandler(_ context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
 	return oscar.SNACMessage{
 	return oscar.SNACMessage{
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.ICBM,
 			FoodGroup: oscar.ICBM,
 			SubGroup:  oscar.ICBMParameterReply,
 			SubGroup:  oscar.ICBMParameterReply,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x04_0x05_ICBMParameterReply{
 		Body: oscar.SNAC_0x04_0x05_ICBMParameterReply{
 			MaxSlots:             100,
 			MaxSlots:             100,
@@ -38,8 +39,8 @@ func (s ICBMService) ParameterQueryHandler(context.Context) oscar.SNACMessage {
 	}
 	}
 }
 }
 
 
-func (s ICBMService) ChannelMsgToHostHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) (*oscar.SNACMessage, error) {
-	blocked, err := s.feedbagManager.Blocked(sess.ScreenName(), snacPayloadIn.ScreenName)
+func (s ICBMService) ChannelMsgToHostHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) (*oscar.SNACMessage, error) {
+	blocked, err := s.feedbagManager.Blocked(sess.ScreenName(), inBody.ScreenName)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -53,6 +54,7 @@ func (s ICBMService) ChannelMsgToHostHandler(ctx context.Context, sess *state.Se
 			Frame: oscar.SNACFrame{
 			Frame: oscar.SNACFrame{
 				FoodGroup: oscar.ICBM,
 				FoodGroup: oscar.ICBM,
 				SubGroup:  oscar.ICBMErr,
 				SubGroup:  oscar.ICBMErr,
+				RequestID: inFrame.RequestID,
 			},
 			},
 			Body: oscar.SNACError{
 			Body: oscar.SNACError{
 				Code: code,
 				Code: code,
@@ -60,12 +62,13 @@ func (s ICBMService) ChannelMsgToHostHandler(ctx context.Context, sess *state.Se
 		}, nil
 		}, nil
 	}
 	}
 
 
-	recipSess := s.sessionManager.RetrieveByScreenName(snacPayloadIn.ScreenName)
+	recipSess := s.sessionManager.RetrieveByScreenName(inBody.ScreenName)
 	if recipSess == nil {
 	if recipSess == nil {
 		return &oscar.SNACMessage{
 		return &oscar.SNACMessage{
 			Frame: oscar.SNACFrame{
 			Frame: oscar.SNACFrame{
 				FoodGroup: oscar.ICBM,
 				FoodGroup: oscar.ICBM,
 				SubGroup:  oscar.ICBMErr,
 				SubGroup:  oscar.ICBMErr,
+				RequestID: inFrame.RequestID,
 			},
 			},
 			Body: oscar.SNACError{
 			Body: oscar.SNACError{
 				Code: oscar.ErrorCodeNotLoggedOn,
 				Code: oscar.ErrorCodeNotLoggedOn,
@@ -74,8 +77,8 @@ func (s ICBMService) ChannelMsgToHostHandler(ctx context.Context, sess *state.Se
 	}
 	}
 
 
 	clientIM := oscar.SNAC_0x04_0x07_ICBMChannelMsgToClient{
 	clientIM := oscar.SNAC_0x04_0x07_ICBMChannelMsgToClient{
-		Cookie:    snacPayloadIn.Cookie,
-		ChannelID: snacPayloadIn.ChannelID,
+		Cookie:    inBody.Cookie,
+		ChannelID: inBody.ChannelID,
 		TLVUserInfo: oscar.TLVUserInfo{
 		TLVUserInfo: oscar.TLVUserInfo{
 			ScreenName:   sess.ScreenName(),
 			ScreenName:   sess.ScreenName(),
 			WarningLevel: sess.Warning(),
 			WarningLevel: sess.Warning(),
@@ -92,17 +95,17 @@ func (s ICBMService) ChannelMsgToHostHandler(ctx context.Context, sess *state.Se
 	// copy over TLVs from sender SNAC to recipient SNAC verbatim. this
 	// copy over TLVs from sender SNAC to recipient SNAC verbatim. this
 	// includes ICBMTLVTagRequestHostAck, which is ignored by the client, as
 	// includes ICBMTLVTagRequestHostAck, which is ignored by the client, as
 	// far as I can tell.
 	// far as I can tell.
-	clientIM.AddTLVList(snacPayloadIn.TLVRestBlock.TLVList)
+	clientIM.AddTLVList(inBody.TLVRestBlock.TLVList)
 
 
 	s.sessionManager.SendToScreenName(ctx, recipSess.ScreenName(), oscar.SNACMessage{
 	s.sessionManager.SendToScreenName(ctx, recipSess.ScreenName(), oscar.SNACMessage{
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.ICBM,
 			FoodGroup: oscar.ICBM,
-			SubGroup:  oscar.ICBMChannelMsgToclient,
+			SubGroup:  oscar.ICBMChannelMsgToClient,
 		},
 		},
 		Body: clientIM,
 		Body: clientIM,
 	})
 	})
 
 
-	if _, requestedConfirmation := snacPayloadIn.TLVRestBlock.GetSlice(oscar.ICBMTLVTagRequestHostAck); !requestedConfirmation {
+	if _, requestedConfirmation := inBody.TLVRestBlock.GetSlice(oscar.ICBMTLVTagRequestHostAck); !requestedConfirmation {
 		// don't ack message
 		// don't ack message
 		return nil, nil
 		return nil, nil
 	}
 	}
@@ -112,17 +115,18 @@ func (s ICBMService) ChannelMsgToHostHandler(ctx context.Context, sess *state.Se
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.ICBM,
 			FoodGroup: oscar.ICBM,
 			SubGroup:  oscar.ICBMHostAck,
 			SubGroup:  oscar.ICBMHostAck,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x04_0x0C_ICBMHostAck{
 		Body: oscar.SNAC_0x04_0x0C_ICBMHostAck{
-			Cookie:     snacPayloadIn.Cookie,
-			ChannelID:  snacPayloadIn.ChannelID,
-			ScreenName: snacPayloadIn.ScreenName,
+			Cookie:     inBody.Cookie,
+			ChannelID:  inBody.ChannelID,
+			ScreenName: inBody.ScreenName,
 		},
 		},
 	}, nil
 	}, nil
 }
 }
 
 
-func (s ICBMService) ClientEventHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x04_0x14_ICBMClientEvent) error {
-	blocked, err := s.feedbagManager.Blocked(sess.ScreenName(), snacPayloadIn.ScreenName)
+func (s ICBMService) ClientEventHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x04_0x14_ICBMClientEvent) error {
+	blocked, err := s.feedbagManager.Blocked(sess.ScreenName(), inBody.ScreenName)
 
 
 	switch {
 	switch {
 	case err != nil:
 	case err != nil:
@@ -130,30 +134,32 @@ func (s ICBMService) ClientEventHandler(ctx context.Context, sess *state.Session
 	case blocked != state.BlockedNo:
 	case blocked != state.BlockedNo:
 		return nil
 		return nil
 	default:
 	default:
-		s.sessionManager.SendToScreenName(ctx, snacPayloadIn.ScreenName, oscar.SNACMessage{
+		s.sessionManager.SendToScreenName(ctx, inBody.ScreenName, oscar.SNACMessage{
 			Frame: oscar.SNACFrame{
 			Frame: oscar.SNACFrame{
 				FoodGroup: oscar.ICBM,
 				FoodGroup: oscar.ICBM,
 				SubGroup:  oscar.ICBMClientEvent,
 				SubGroup:  oscar.ICBMClientEvent,
+				RequestID: inFrame.RequestID,
 			},
 			},
 			Body: oscar.SNAC_0x04_0x14_ICBMClientEvent{
 			Body: oscar.SNAC_0x04_0x14_ICBMClientEvent{
-				Cookie:     snacPayloadIn.Cookie,
-				ChannelID:  snacPayloadIn.ChannelID,
+				Cookie:     inBody.Cookie,
+				ChannelID:  inBody.ChannelID,
 				ScreenName: sess.ScreenName(),
 				ScreenName: sess.ScreenName(),
-				Event:      snacPayloadIn.Event,
+				Event:      inBody.Event,
 			},
 			},
 		})
 		})
 		return nil
 		return nil
 	}
 	}
 }
 }
 
 
-func (s ICBMService) EvilRequestHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x04_0x08_ICBMEvilRequest) (oscar.SNACMessage, error) {
+func (s ICBMService) EvilRequestHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x04_0x08_ICBMEvilRequest) (oscar.SNACMessage, error) {
 	// don't let users warn themselves, it causes the AIM client to go into a
 	// don't let users warn themselves, it causes the AIM client to go into a
 	// weird state.
 	// weird state.
-	if snacPayloadIn.ScreenName == sess.ScreenName() {
+	if inBody.ScreenName == sess.ScreenName() {
 		return oscar.SNACMessage{
 		return oscar.SNACMessage{
 			Frame: oscar.SNACFrame{
 			Frame: oscar.SNACFrame{
 				FoodGroup: oscar.ICBM,
 				FoodGroup: oscar.ICBM,
 				SubGroup:  oscar.ICBMErr,
 				SubGroup:  oscar.ICBMErr,
+				RequestID: inFrame.RequestID,
 			},
 			},
 			Body: oscar.SNACError{
 			Body: oscar.SNACError{
 				Code: oscar.ErrorCodeNotSupportedByHost,
 				Code: oscar.ErrorCodeNotSupportedByHost,
@@ -161,7 +167,7 @@ func (s ICBMService) EvilRequestHandler(ctx context.Context, sess *state.Session
 		}, nil
 		}, nil
 	}
 	}
 
 
-	blocked, err := s.feedbagManager.Blocked(sess.ScreenName(), snacPayloadIn.ScreenName)
+	blocked, err := s.feedbagManager.Blocked(sess.ScreenName(), inBody.ScreenName)
 	if err != nil {
 	if err != nil {
 		return oscar.SNACMessage{}, nil
 		return oscar.SNACMessage{}, nil
 	}
 	}
@@ -170,6 +176,7 @@ func (s ICBMService) EvilRequestHandler(ctx context.Context, sess *state.Session
 			Frame: oscar.SNACFrame{
 			Frame: oscar.SNACFrame{
 				FoodGroup: oscar.ICBM,
 				FoodGroup: oscar.ICBM,
 				SubGroup:  oscar.ICBMErr,
 				SubGroup:  oscar.ICBMErr,
+				RequestID: inFrame.RequestID,
 			},
 			},
 			Body: oscar.SNACError{
 			Body: oscar.SNACError{
 				Code: oscar.ErrorCodeNotLoggedOn,
 				Code: oscar.ErrorCodeNotLoggedOn,
@@ -177,19 +184,19 @@ func (s ICBMService) EvilRequestHandler(ctx context.Context, sess *state.Session
 		}, nil
 		}, nil
 	}
 	}
 
 
-	recipSess := s.sessionManager.RetrieveByScreenName(snacPayloadIn.ScreenName)
+	recipSess := s.sessionManager.RetrieveByScreenName(inBody.ScreenName)
 	if recipSess == nil {
 	if recipSess == nil {
 		return oscar.SNACMessage{}, nil
 		return oscar.SNACMessage{}, nil
 	}
 	}
 
 
 	increase := evilDelta
 	increase := evilDelta
-	if snacPayloadIn.SendAs == 1 {
+	if inBody.SendAs == 1 {
 		increase = evilDeltaAnon
 		increase = evilDeltaAnon
 	}
 	}
 	recipSess.IncreaseWarning(increase)
 	recipSess.IncreaseWarning(increase)
 
 
 	var notif any
 	var notif any
-	if snacPayloadIn.SendAs == 0 {
+	if inBody.SendAs == 0 {
 		notif = oscar.SNAC_0x01_0x10_OServiceEvilNotification{
 		notif = oscar.SNAC_0x01_0x10_OServiceEvilNotification{
 			NewEvil: recipSess.Warning(),
 			NewEvil: recipSess.Warning(),
 			TLVUserInfo: oscar.TLVUserInfo{
 			TLVUserInfo: oscar.TLVUserInfo{
@@ -219,6 +226,7 @@ func (s ICBMService) EvilRequestHandler(ctx context.Context, sess *state.Session
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.ICBM,
 			FoodGroup: oscar.ICBM,
 			SubGroup:  oscar.ICBMEvilReply,
 			SubGroup:  oscar.ICBMEvilReply,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x04_0x09_ICBMEvilReply{
 		Body: oscar.SNAC_0x04_0x09_ICBMEvilReply{
 			EvilDeltaApplied: increase,
 			EvilDeltaApplied: increase,

+ 142 - 67
handler/icbm_test.go

@@ -9,7 +9,7 @@ import (
 	"github.com/stretchr/testify/mock"
 	"github.com/stretchr/testify/mock"
 )
 )
 
 
-func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
+func TestSendAndReceiveChannelMsgToHost(t *testing.T) {
 	cases := []struct {
 	cases := []struct {
 		// name is the unit test name
 		// name is the unit test name
 		name string
 		name string
@@ -21,7 +21,7 @@ func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
 		senderSession    *state.Session
 		senderSession    *state.Session
 		recipientSession *state.Session
 		recipientSession *state.Session
 		// inputSNAC is the SNAC sent by the sender client
 		// inputSNAC is the SNAC sent by the sender client
-		inputSNAC oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost
+		inputSNAC oscar.SNACMessage
 		// expectSNACToClient is the SNAC sent from the server to the
 		// expectSNACToClient is the SNAC sent from the server to the
 		// recipient client
 		// recipient client
 		expectSNACToClient oscar.SNACMessage
 		expectSNACToClient oscar.SNACMessage
@@ -34,13 +34,18 @@ func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
 			blockedState:     state.BlockedNo,
 			blockedState:     state.BlockedNo,
 			senderSession:    newTestSession("sender-screen-name", sessOptWarning(10)),
 			senderSession:    newTestSession("sender-screen-name", sessOptWarning(10)),
 			recipientSession: newTestSession("recipient-screen-name", sessOptWarning(20)),
 			recipientSession: newTestSession("recipient-screen-name", sessOptWarning(20)),
-			inputSNAC: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
-				ScreenName: "recipient-screen-name",
-				TLVRestBlock: oscar.TLVRestBlock{
-					TLVList: oscar.TLVList{
-						{
-							TType: oscar.ICBMTLVTagRequestHostAck,
-							Val:   []byte{},
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
+					ScreenName: "recipient-screen-name",
+					TLVRestBlock: oscar.TLVRestBlock{
+						TLVList: oscar.TLVList{
+							{
+								TType: oscar.ICBMTLVTagRequestHostAck,
+								Val:   []byte{},
+							},
 						},
 						},
 					},
 					},
 				},
 				},
@@ -48,7 +53,7 @@ func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
 			expectSNACToClient: oscar.SNACMessage{
 			expectSNACToClient: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.ICBM,
 					FoodGroup: oscar.ICBM,
-					SubGroup:  oscar.ICBMChannelMsgToclient,
+					SubGroup:  oscar.ICBMChannelMsgToClient,
 				},
 				},
 				Body: oscar.SNAC_0x04_0x07_ICBMChannelMsgToClient{
 				Body: oscar.SNAC_0x04_0x07_ICBMChannelMsgToClient{
 					TLVUserInfo: oscar.TLVUserInfo{
 					TLVUserInfo: oscar.TLVUserInfo{
@@ -73,6 +78,7 @@ func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.ICBM,
 					FoodGroup: oscar.ICBM,
 					SubGroup:  oscar.ICBMHostAck,
 					SubGroup:  oscar.ICBMHostAck,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x04_0x0C_ICBMHostAck{
 				Body: oscar.SNAC_0x04_0x0C_ICBMHostAck{
 					ScreenName: "recipient-screen-name",
 					ScreenName: "recipient-screen-name",
@@ -84,16 +90,21 @@ func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
 			blockedState:     state.BlockedNo,
 			blockedState:     state.BlockedNo,
 			senderSession:    newTestSession("sender-screen-name", sessOptWarning(10)),
 			senderSession:    newTestSession("sender-screen-name", sessOptWarning(10)),
 			recipientSession: newTestSession("recipient-screen-name", sessOptWarning(20)),
 			recipientSession: newTestSession("recipient-screen-name", sessOptWarning(20)),
-			inputSNAC: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
-				ScreenName: "recipient-screen-name",
-				TLVRestBlock: oscar.TLVRestBlock{
-					TLVList: oscar.TLVList{},
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
+					ScreenName: "recipient-screen-name",
+					TLVRestBlock: oscar.TLVRestBlock{
+						TLVList: oscar.TLVList{},
+					},
 				},
 				},
 			},
 			},
 			expectSNACToClient: oscar.SNACMessage{
 			expectSNACToClient: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.ICBM,
 					FoodGroup: oscar.ICBM,
-					SubGroup:  oscar.ICBMChannelMsgToclient,
+					SubGroup:  oscar.ICBMChannelMsgToClient,
 				},
 				},
 				Body: oscar.SNAC_0x04_0x07_ICBMChannelMsgToClient{
 				Body: oscar.SNAC_0x04_0x07_ICBMChannelMsgToClient{
 					TLVUserInfo: oscar.TLVUserInfo{
 					TLVUserInfo: oscar.TLVUserInfo{
@@ -117,13 +128,18 @@ func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
 			blockedState:     state.BlockedA,
 			blockedState:     state.BlockedA,
 			senderSession:    newTestSession("sender-screen-name", sessOptWarning(10)),
 			senderSession:    newTestSession("sender-screen-name", sessOptWarning(10)),
 			recipientSession: newTestSession("recipient-screen-name", sessOptWarning(20)),
 			recipientSession: newTestSession("recipient-screen-name", sessOptWarning(20)),
-			inputSNAC: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
-				ScreenName: "recipient-screen-name",
-				TLVRestBlock: oscar.TLVRestBlock{
-					TLVList: oscar.TLVList{
-						{
-							TType: oscar.ICBMTLVTagRequestHostAck,
-							Val:   []byte{},
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
+					ScreenName: "recipient-screen-name",
+					TLVRestBlock: oscar.TLVRestBlock{
+						TLVList: oscar.TLVList{
+							{
+								TType: oscar.ICBMTLVTagRequestHostAck,
+								Val:   []byte{},
+							},
 						},
 						},
 					},
 					},
 				},
 				},
@@ -132,6 +148,7 @@ func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.ICBM,
 					FoodGroup: oscar.ICBM,
 					SubGroup:  oscar.ICBMErr,
 					SubGroup:  oscar.ICBMErr,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNACError{
 				Body: oscar.SNACError{
 					Code: oscar.ErrorCodeInLocalPermitDeny,
 					Code: oscar.ErrorCodeInLocalPermitDeny,
@@ -143,13 +160,18 @@ func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
 			blockedState:     state.BlockedB,
 			blockedState:     state.BlockedB,
 			senderSession:    newTestSession("sender-screen-name", sessOptWarning(10)),
 			senderSession:    newTestSession("sender-screen-name", sessOptWarning(10)),
 			recipientSession: newTestSession("recipient-screen-name", sessOptWarning(20)),
 			recipientSession: newTestSession("recipient-screen-name", sessOptWarning(20)),
-			inputSNAC: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
-				ScreenName: "recipient-screen-name",
-				TLVRestBlock: oscar.TLVRestBlock{
-					TLVList: oscar.TLVList{
-						{
-							TType: oscar.ICBMTLVTagRequestHostAck,
-							Val:   []byte{},
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
+					ScreenName: "recipient-screen-name",
+					TLVRestBlock: oscar.TLVRestBlock{
+						TLVList: oscar.TLVList{
+							{
+								TType: oscar.ICBMTLVTagRequestHostAck,
+								Val:   []byte{},
+							},
 						},
 						},
 					},
 					},
 				},
 				},
@@ -158,6 +180,7 @@ func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.ICBM,
 					FoodGroup: oscar.ICBM,
 					SubGroup:  oscar.ICBMErr,
 					SubGroup:  oscar.ICBMErr,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNACError{
 				Body: oscar.SNACError{
 					Code: oscar.ErrorCodeNotLoggedOn,
 					Code: oscar.ErrorCodeNotLoggedOn,
@@ -169,13 +192,18 @@ func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
 			blockedState:     state.BlockedNo,
 			blockedState:     state.BlockedNo,
 			senderSession:    newTestSession("sender-screen-name", sessOptWarning(10)),
 			senderSession:    newTestSession("sender-screen-name", sessOptWarning(10)),
 			recipientSession: nil,
 			recipientSession: nil,
-			inputSNAC: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
-				ScreenName: "recipient-screen-name",
-				TLVRestBlock: oscar.TLVRestBlock{
-					TLVList: oscar.TLVList{
-						{
-							TType: oscar.ICBMTLVTagRequestHostAck,
-							Val:   []byte{},
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
+					ScreenName: "recipient-screen-name",
+					TLVRestBlock: oscar.TLVRestBlock{
+						TLVList: oscar.TLVList{
+							{
+								TType: oscar.ICBMTLVTagRequestHostAck,
+								Val:   []byte{},
+							},
 						},
 						},
 					},
 					},
 				},
 				},
@@ -184,6 +212,7 @@ func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.ICBM,
 					FoodGroup: oscar.ICBM,
 					SubGroup:  oscar.ICBMErr,
 					SubGroup:  oscar.ICBMErr,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNACError{
 				Body: oscar.SNACError{
 					Code: oscar.ErrorCodeNotLoggedOn,
 					Code: oscar.ErrorCodeNotLoggedOn,
@@ -199,12 +228,13 @@ func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
 			//
 			//
 			fm := newMockFeedbagManager(t)
 			fm := newMockFeedbagManager(t)
 			fm.EXPECT().
 			fm.EXPECT().
-				Blocked(tc.senderSession.ScreenName(), tc.inputSNAC.ScreenName).
+				Blocked(tc.senderSession.ScreenName(),
+					tc.inputSNAC.Body.(oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost).ScreenName).
 				Return(tc.blockedState, nil).
 				Return(tc.blockedState, nil).
 				Maybe()
 				Maybe()
 			sm := newMockSessionManager(t)
 			sm := newMockSessionManager(t)
 			sm.EXPECT().
 			sm.EXPECT().
-				RetrieveByScreenName(tc.inputSNAC.ScreenName).
+				RetrieveByScreenName(tc.inputSNAC.Body.(oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost).ScreenName).
 				Return(tc.recipientSession).
 				Return(tc.recipientSession).
 				Maybe()
 				Maybe()
 			if tc.recipientSession != nil {
 			if tc.recipientSession != nil {
@@ -219,7 +249,8 @@ func TestSendAndReceiveChannelMsgTohost(t *testing.T) {
 				sessionManager: sm,
 				sessionManager: sm,
 				feedbagManager: fm,
 				feedbagManager: fm,
 			}
 			}
-			outputSNAC, err := svc.ChannelMsgToHostHandler(nil, tc.senderSession, tc.inputSNAC)
+			outputSNAC, err := svc.ChannelMsgToHostHandler(nil, tc.senderSession, tc.inputSNAC.Frame,
+				tc.inputSNAC.Body.(oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost))
 			assert.NoError(t, err)
 			assert.NoError(t, err)
 			//
 			//
 			// verify output
 			// verify output
@@ -238,7 +269,7 @@ func TestSendAndReceiveClientEvent(t *testing.T) {
 		// senderScreenName is the screen name of the user sending the event
 		// senderScreenName is the screen name of the user sending the event
 		senderScreenName string
 		senderScreenName string
 		// inputSNAC is the SNAC sent by the sender client
 		// inputSNAC is the SNAC sent by the sender client
-		inputSNAC oscar.SNAC_0x04_0x14_ICBMClientEvent
+		inputSNAC oscar.SNACMessage
 		// expectSNACToClient is the SNAC sent from the server to the
 		// expectSNACToClient is the SNAC sent from the server to the
 		// recipient client
 		// recipient client
 		expectSNACToClient oscar.SNACMessage
 		expectSNACToClient oscar.SNACMessage
@@ -247,16 +278,22 @@ func TestSendAndReceiveClientEvent(t *testing.T) {
 			name:             "transmit message from sender to recipient",
 			name:             "transmit message from sender to recipient",
 			blockedState:     state.BlockedNo,
 			blockedState:     state.BlockedNo,
 			senderScreenName: "sender-screen-name",
 			senderScreenName: "sender-screen-name",
-			inputSNAC: oscar.SNAC_0x04_0x14_ICBMClientEvent{
-				Cookie:     [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
-				ChannelID:  42,
-				ScreenName: "recipient-screen-name",
-				Event:      12,
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x04_0x14_ICBMClientEvent{
+					Cookie:     [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
+					ChannelID:  42,
+					ScreenName: "recipient-screen-name",
+					Event:      12,
+				},
 			},
 			},
 			expectSNACToClient: oscar.SNACMessage{
 			expectSNACToClient: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.ICBM,
 					FoodGroup: oscar.ICBM,
 					SubGroup:  oscar.ICBMClientEvent,
 					SubGroup:  oscar.ICBMClientEvent,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x04_0x14_ICBMClientEvent{
 				Body: oscar.SNAC_0x04_0x14_ICBMClientEvent{
 					Cookie:     [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
 					Cookie:     [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
@@ -270,8 +307,13 @@ func TestSendAndReceiveClientEvent(t *testing.T) {
 			name:             "don't transmit message from sender to recipient because sender has blocked recipient",
 			name:             "don't transmit message from sender to recipient because sender has blocked recipient",
 			blockedState:     state.BlockedA,
 			blockedState:     state.BlockedA,
 			senderScreenName: "sender-screen-name",
 			senderScreenName: "sender-screen-name",
-			inputSNAC: oscar.SNAC_0x04_0x14_ICBMClientEvent{
-				ScreenName: "recipient-screen-name",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x04_0x14_ICBMClientEvent{
+					ScreenName: "recipient-screen-name",
+				},
 			},
 			},
 		},
 		},
 	}
 	}
@@ -283,13 +325,14 @@ func TestSendAndReceiveClientEvent(t *testing.T) {
 			//
 			//
 			fm := newMockFeedbagManager(t)
 			fm := newMockFeedbagManager(t)
 			fm.EXPECT().
 			fm.EXPECT().
-				Blocked(tc.senderScreenName, tc.inputSNAC.ScreenName).
+				Blocked(tc.senderScreenName, tc.inputSNAC.Body.(oscar.SNAC_0x04_0x14_ICBMClientEvent).ScreenName).
 				Return(tc.blockedState, nil).
 				Return(tc.blockedState, nil).
 				Maybe()
 				Maybe()
 			sm := newMockSessionManager(t)
 			sm := newMockSessionManager(t)
 			if tc.blockedState == state.BlockedNo {
 			if tc.blockedState == state.BlockedNo {
 				sm.EXPECT().
 				sm.EXPECT().
-					SendToScreenName(mock.Anything, tc.inputSNAC.ScreenName, tc.expectSNACToClient)
+					SendToScreenName(mock.Anything, tc.inputSNAC.Body.(oscar.SNAC_0x04_0x14_ICBMClientEvent).ScreenName,
+						tc.expectSNACToClient)
 			}
 			}
 			//
 			//
 			// send input SNAC
 			// send input SNAC
@@ -299,7 +342,8 @@ func TestSendAndReceiveClientEvent(t *testing.T) {
 				sessionManager: sm,
 				sessionManager: sm,
 				feedbagManager: fm,
 				feedbagManager: fm,
 			}
 			}
-			assert.NoError(t, svc.ClientEventHandler(nil, senderSession, tc.inputSNAC))
+			assert.NoError(t, svc.ClientEventHandler(nil, senderSession, tc.inputSNAC.Frame,
+				tc.inputSNAC.Body.(oscar.SNAC_0x04_0x14_ICBMClientEvent)))
 		})
 		})
 	}
 	}
 }
 }
@@ -322,7 +366,7 @@ func TestSendAndReceiveEvilRequest(t *testing.T) {
 		recipientBuddies []string
 		recipientBuddies []string
 		broadcastMessage oscar.SNACMessage
 		broadcastMessage oscar.SNACMessage
 		// inputSNAC is the SNAC sent by the sender client
 		// inputSNAC is the SNAC sent by the sender client
-		inputSNAC oscar.SNAC_0x04_0x08_ICBMEvilRequest
+		inputSNAC oscar.SNACMessage
 		// expectSNACToClient is the SNAC sent from the server to the
 		// expectSNACToClient is the SNAC sent from the server to the
 		// recipient client
 		// recipient client
 		expectSNACToClient oscar.SNACMessage
 		expectSNACToClient oscar.SNACMessage
@@ -350,9 +394,14 @@ func TestSendAndReceiveEvilRequest(t *testing.T) {
 				},
 				},
 			},
 			},
 			recipientBuddies: []string{"buddy1", "buddy2"},
 			recipientBuddies: []string{"buddy1", "buddy2"},
-			inputSNAC: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
-				SendAs:     1, // make it anonymous
-				ScreenName: "recipient-screen-name",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
+					SendAs:     1, // make it anonymous
+					ScreenName: "recipient-screen-name",
+				},
 			},
 			},
 			expectSNACToClient: oscar.SNACMessage{
 			expectSNACToClient: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
@@ -367,6 +416,7 @@ func TestSendAndReceiveEvilRequest(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.ICBM,
 					FoodGroup: oscar.ICBM,
 					SubGroup:  oscar.ICBMEvilReply,
 					SubGroup:  oscar.ICBMEvilReply,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x04_0x09_ICBMEvilReply{
 				Body: oscar.SNAC_0x04_0x09_ICBMEvilReply{
 					EvilDeltaApplied: 30,
 					EvilDeltaApplied: 30,
@@ -395,9 +445,14 @@ func TestSendAndReceiveEvilRequest(t *testing.T) {
 					},
 					},
 				},
 				},
 			},
 			},
-			inputSNAC: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
-				SendAs:     0, // make it identified
-				ScreenName: "recipient-screen-name",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
+					SendAs:     0, // make it identified
+					ScreenName: "recipient-screen-name",
+				},
 			},
 			},
 			expectSNACToClient: oscar.SNACMessage{
 			expectSNACToClient: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
@@ -416,6 +471,7 @@ func TestSendAndReceiveEvilRequest(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.ICBM,
 					FoodGroup: oscar.ICBM,
 					SubGroup:  oscar.ICBMEvilReply,
 					SubGroup:  oscar.ICBMEvilReply,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x04_0x09_ICBMEvilReply{
 				Body: oscar.SNAC_0x04_0x09_ICBMEvilReply{
 					EvilDeltaApplied: 100,
 					EvilDeltaApplied: 100,
@@ -429,14 +485,20 @@ func TestSendAndReceiveEvilRequest(t *testing.T) {
 			senderSession:       newTestSession("sender-screen-name"),
 			senderSession:       newTestSession("sender-screen-name"),
 			recipientScreenName: "recipient-screen-name",
 			recipientScreenName: "recipient-screen-name",
 			recipientBuddies:    []string{"buddy1", "buddy2"},
 			recipientBuddies:    []string{"buddy1", "buddy2"},
-			inputSNAC: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
-				SendAs:     0, // make it identified
-				ScreenName: "recipient-screen-name",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
+					SendAs:     0, // make it identified
+					ScreenName: "recipient-screen-name",
+				},
 			},
 			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.ICBM,
 					FoodGroup: oscar.ICBM,
 					SubGroup:  oscar.ICBMErr,
 					SubGroup:  oscar.ICBMErr,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNACError{
 				Body: oscar.SNACError{
 					Code: oscar.ErrorCodeNotLoggedOn,
 					Code: oscar.ErrorCodeNotLoggedOn,
@@ -449,14 +511,20 @@ func TestSendAndReceiveEvilRequest(t *testing.T) {
 			senderSession:       newTestSession("sender-screen-name"),
 			senderSession:       newTestSession("sender-screen-name"),
 			recipientScreenName: "recipient-screen-name",
 			recipientScreenName: "recipient-screen-name",
 			recipientBuddies:    []string{"buddy1", "buddy2"},
 			recipientBuddies:    []string{"buddy1", "buddy2"},
-			inputSNAC: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
-				SendAs:     0, // make it identified
-				ScreenName: "recipient-screen-name",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
+					SendAs:     0, // make it identified
+					ScreenName: "recipient-screen-name",
+				},
 			},
 			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.ICBM,
 					FoodGroup: oscar.ICBM,
 					SubGroup:  oscar.ICBMErr,
 					SubGroup:  oscar.ICBMErr,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNACError{
 				Body: oscar.SNACError{
 					Code: oscar.ErrorCodeNotLoggedOn,
 					Code: oscar.ErrorCodeNotLoggedOn,
@@ -467,14 +535,20 @@ func TestSendAndReceiveEvilRequest(t *testing.T) {
 			name:                "don't let users block themselves",
 			name:                "don't let users block themselves",
 			senderSession:       newTestSession("sender-screen-name"),
 			senderSession:       newTestSession("sender-screen-name"),
 			recipientScreenName: "sender-screen-name",
 			recipientScreenName: "sender-screen-name",
-			inputSNAC: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
-				SendAs:     0, // make it identified
-				ScreenName: "sender-screen-name",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
+					SendAs:     0, // make it identified
+					ScreenName: "sender-screen-name",
+				},
 			},
 			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.ICBM,
 					FoodGroup: oscar.ICBM,
 					SubGroup:  oscar.ICBMErr,
 					SubGroup:  oscar.ICBMErr,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNACError{
 				Body: oscar.SNACError{
 					Code: oscar.ErrorCodeNotSupportedByHost,
 					Code: oscar.ErrorCodeNotSupportedByHost,
@@ -517,7 +591,8 @@ func TestSendAndReceiveEvilRequest(t *testing.T) {
 				sessionManager: sm,
 				sessionManager: sm,
 				feedbagManager: fm,
 				feedbagManager: fm,
 			}
 			}
-			outputSNAC, err := svc.EvilRequestHandler(nil, senderSession, tc.inputSNAC)
+			outputSNAC, err := svc.EvilRequestHandler(nil, senderSession, tc.inputSNAC.Frame,
+				tc.inputSNAC.Body.(oscar.SNAC_0x04_0x08_ICBMEvilRequest))
 			assert.NoError(t, err)
 			assert.NoError(t, err)
 			assert.Equal(t, tc.expectOutput, outputSNAC)
 			assert.Equal(t, tc.expectOutput, outputSNAC)
 		})
 		})

+ 16 - 11
handler/locate.go

@@ -21,11 +21,12 @@ type LocateService struct {
 	profileManager ProfileManager
 	profileManager ProfileManager
 }
 }
 
 
-func (s LocateService) RightsQueryHandler(context.Context) oscar.SNACMessage {
+func (s LocateService) RightsQueryHandler(_ context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
 	return oscar.SNACMessage{
 	return oscar.SNACMessage{
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.Locate,
 			FoodGroup: oscar.Locate,
 			SubGroup:  oscar.LocateRightsReply,
 			SubGroup:  oscar.LocateRightsReply,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x02_0x03_LocateRightsReply{
 		Body: oscar.SNAC_0x02_0x03_LocateRightsReply{
 			TLVRestBlock: oscar.TLVRestBlock{
 			TLVRestBlock: oscar.TLVRestBlock{
@@ -41,16 +42,16 @@ func (s LocateService) RightsQueryHandler(context.Context) oscar.SNACMessage {
 	}
 	}
 }
 }
 
 
-func (s LocateService) SetInfoHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x02_0x04_LocateSetInfo) error {
+func (s LocateService) SetInfoHandler(ctx context.Context, sess *state.Session, inBody oscar.SNAC_0x02_0x04_LocateSetInfo) error {
 	// update profile
 	// update profile
-	if profile, hasProfile := snacPayloadIn.GetString(oscar.LocateTLVTagsInfoSigData); hasProfile {
+	if profile, hasProfile := inBody.GetString(oscar.LocateTLVTagsInfoSigData); hasProfile {
 		if err := s.profileManager.UpsertProfile(sess.ScreenName(), profile); err != nil {
 		if err := s.profileManager.UpsertProfile(sess.ScreenName(), profile); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
 
 
 	// broadcast away message change to buddies
 	// broadcast away message change to buddies
-	if awayMsg, hasAwayMsg := snacPayloadIn.GetString(oscar.LocateTLVTagsInfoUnavailableData); hasAwayMsg {
+	if awayMsg, hasAwayMsg := inBody.GetString(oscar.LocateTLVTagsInfoUnavailableData); hasAwayMsg {
 		sess.SetAwayMessage(awayMsg)
 		sess.SetAwayMessage(awayMsg)
 		if err := broadcastArrival(ctx, sess, s.sessionManager, s.feedbagManager); err != nil {
 		if err := broadcastArrival(ctx, sess, s.sessionManager, s.feedbagManager); err != nil {
 			return err
 			return err
@@ -59,8 +60,8 @@ func (s LocateService) SetInfoHandler(ctx context.Context, sess *state.Session,
 	return nil
 	return nil
 }
 }
 
 
-func (s LocateService) UserInfoQuery2Handler(_ context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) (oscar.SNACMessage, error) {
-	blocked, err := s.feedbagManager.Blocked(sess.ScreenName(), snacPayloadIn.ScreenName)
+func (s LocateService) UserInfoQuery2Handler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) (oscar.SNACMessage, error) {
+	blocked, err := s.feedbagManager.Blocked(sess.ScreenName(), inBody.ScreenName)
 	switch {
 	switch {
 	case err != nil:
 	case err != nil:
 		return oscar.SNACMessage{}, err
 		return oscar.SNACMessage{}, err
@@ -69,6 +70,7 @@ func (s LocateService) UserInfoQuery2Handler(_ context.Context, sess *state.Sess
 			Frame: oscar.SNACFrame{
 			Frame: oscar.SNACFrame{
 				FoodGroup: oscar.Locate,
 				FoodGroup: oscar.Locate,
 				SubGroup:  oscar.LocateErr,
 				SubGroup:  oscar.LocateErr,
+				RequestID: inFrame.RequestID,
 			},
 			},
 			Body: oscar.SNACError{
 			Body: oscar.SNACError{
 				Code: oscar.ErrorCodeNotLoggedOn,
 				Code: oscar.ErrorCodeNotLoggedOn,
@@ -76,12 +78,13 @@ func (s LocateService) UserInfoQuery2Handler(_ context.Context, sess *state.Sess
 		}, nil
 		}, nil
 	}
 	}
 
 
-	buddySess := s.sessionManager.RetrieveByScreenName(snacPayloadIn.ScreenName)
+	buddySess := s.sessionManager.RetrieveByScreenName(inBody.ScreenName)
 	if buddySess == nil {
 	if buddySess == nil {
 		return oscar.SNACMessage{
 		return oscar.SNACMessage{
 			Frame: oscar.SNACFrame{
 			Frame: oscar.SNACFrame{
 				FoodGroup: oscar.Locate,
 				FoodGroup: oscar.Locate,
 				SubGroup:  oscar.LocateErr,
 				SubGroup:  oscar.LocateErr,
+				RequestID: inFrame.RequestID,
 			},
 			},
 			Body: oscar.SNACError{
 			Body: oscar.SNACError{
 				Code: oscar.ErrorCodeNotLoggedOn,
 				Code: oscar.ErrorCodeNotLoggedOn,
@@ -91,8 +94,8 @@ func (s LocateService) UserInfoQuery2Handler(_ context.Context, sess *state.Sess
 
 
 	var list oscar.TLVList
 	var list oscar.TLVList
 
 
-	if snacPayloadIn.RequestProfile() {
-		profile, err := s.profileManager.RetrieveProfile(snacPayloadIn.ScreenName)
+	if inBody.RequestProfile() {
+		profile, err := s.profileManager.RetrieveProfile(inBody.ScreenName)
 		if err != nil {
 		if err != nil {
 			return oscar.SNACMessage{}, err
 			return oscar.SNACMessage{}, err
 		}
 		}
@@ -102,7 +105,7 @@ func (s LocateService) UserInfoQuery2Handler(_ context.Context, sess *state.Sess
 		})
 		})
 	}
 	}
 
 
-	if snacPayloadIn.RequestAwayMessage() {
+	if inBody.RequestAwayMessage() {
 		list.AddTLVList([]oscar.TLV{
 		list.AddTLVList([]oscar.TLV{
 			oscar.NewTLV(oscar.LocateTLVTagsInfoUnavailableMime, `text/aolrtf; charset="us-ascii"`),
 			oscar.NewTLV(oscar.LocateTLVTagsInfoUnavailableMime, `text/aolrtf; charset="us-ascii"`),
 			oscar.NewTLV(oscar.LocateTLVTagsInfoUnavailableData, buddySess.AwayMessage()),
 			oscar.NewTLV(oscar.LocateTLVTagsInfoUnavailableData, buddySess.AwayMessage()),
@@ -113,6 +116,7 @@ func (s LocateService) UserInfoQuery2Handler(_ context.Context, sess *state.Sess
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.Locate,
 			FoodGroup: oscar.Locate,
 			SubGroup:  oscar.LocateUserInfoReply,
 			SubGroup:  oscar.LocateUserInfoReply,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
 		Body: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
 			TLVUserInfo: buddySess.TLVUserInfo(),
 			TLVUserInfo: buddySess.TLVUserInfo(),
@@ -135,11 +139,12 @@ func (s LocateService) SetDirInfoHandler(_ context.Context) oscar.SNACMessage {
 	}
 	}
 }
 }
 
 
-func (s LocateService) SetKeywordInfoHandler(_ context.Context) oscar.SNACMessage {
+func (s LocateService) SetKeywordInfoHandler(_ context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
 	return oscar.SNACMessage{
 	return oscar.SNACMessage{
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.Locate,
 			FoodGroup: oscar.Locate,
 			SubGroup:  oscar.LocateSetKeywordReply,
 			SubGroup:  oscar.LocateSetKeywordReply,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x02_0x10_LocateSetKeywordReply{
 		Body: oscar.SNAC_0x02_0x10_LocateSetKeywordReply{
 			Unknown: 1,
 			Unknown: 1,

+ 62 - 23
handler/locate_test.go

@@ -28,7 +28,9 @@ func TestSendAndReceiveUserInfoQuery2(t *testing.T) {
 		// userSession is the session of the user requesting the user info
 		// userSession is the session of the user requesting the user info
 		userSession *state.Session
 		userSession *state.Session
 		// inputSNAC is the SNAC sent by the sender client
 		// inputSNAC is the SNAC sent by the sender client
-		inputSNAC    oscar.SNAC_0x02_0x15_LocateUserInfoQuery2
+		inputSNAC oscar.SNACMessage
+		// expectOutput is the SNAC sent from the server to the
+		// recipient client
 		expectOutput oscar.SNACMessage
 		expectOutput oscar.SNACMessage
 	}{
 	}{
 		{
 		{
@@ -45,14 +47,20 @@ func TestSendAndReceiveUserInfoQuery2(t *testing.T) {
 				},
 				},
 			},
 			},
 			userSession: newTestSession("user_screen_name"),
 			userSession: newTestSession("user_screen_name"),
-			inputSNAC: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
-				Type2:      0,
-				ScreenName: "requested-user",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
+					Type2:      0,
+					ScreenName: "requested-user",
+				},
 			},
 			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Locate,
 					FoodGroup: oscar.Locate,
 					SubGroup:  oscar.LocateUserInfoReply,
 					SubGroup:  oscar.LocateUserInfoReply,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
 				Body: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
 					TLVUserInfo: newTestSession("requested-user",
 					TLVUserInfo: newTestSession("requested-user",
@@ -85,15 +93,21 @@ func TestSendAndReceiveUserInfoQuery2(t *testing.T) {
 				},
 				},
 			},
 			},
 			userSession: newTestSession("user_screen_name"),
 			userSession: newTestSession("user_screen_name"),
-			inputSNAC: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
-				// 2048 is a dummy to make sure bitmask check works
-				Type2:      oscar.LocateType2Sig | 2048,
-				ScreenName: "requested-user",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
+					// 2048 is a dummy to make sure bitmask check works
+					Type2:      oscar.LocateType2Sig | 2048,
+					ScreenName: "requested-user",
+				},
 			},
 			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Locate,
 					FoodGroup: oscar.Locate,
 					SubGroup:  oscar.LocateUserInfoReply,
 					SubGroup:  oscar.LocateUserInfoReply,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
 				Body: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
 					TLVUserInfo: newTestSession("requested-user",
 					TLVUserInfo: newTestSession("requested-user",
@@ -131,15 +145,21 @@ func TestSendAndReceiveUserInfoQuery2(t *testing.T) {
 				},
 				},
 			},
 			},
 			userSession: newTestSession("user_screen_name"),
 			userSession: newTestSession("user_screen_name"),
-			inputSNAC: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
-				// 2048 is a dummy to make sure bitmask check works
-				Type2:      oscar.LocateType2Sig | 2048,
-				ScreenName: "requested-user",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
+					// 2048 is a dummy to make sure bitmask check works
+					Type2:      oscar.LocateType2Sig | 2048,
+					ScreenName: "requested-user",
+				},
 			},
 			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Locate,
 					FoodGroup: oscar.Locate,
 					SubGroup:  oscar.LocateUserInfoReply,
 					SubGroup:  oscar.LocateUserInfoReply,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
 				Body: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
 					TLVUserInfo: newTestSession("requested-user",
 					TLVUserInfo: newTestSession("requested-user",
@@ -169,15 +189,21 @@ func TestSendAndReceiveUserInfoQuery2(t *testing.T) {
 				},
 				},
 			},
 			},
 			userSession: newTestSession("user_screen_name"),
 			userSession: newTestSession("user_screen_name"),
-			inputSNAC: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
-				// 2048 is a dummy to make sure bitmask check works
-				Type2:      oscar.LocateType2Unavailable | 2048,
-				ScreenName: "requested-user",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
+					// 2048 is a dummy to make sure bitmask check works
+					Type2:      oscar.LocateType2Unavailable | 2048,
+					ScreenName: "requested-user",
+				},
 			},
 			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Locate,
 					FoodGroup: oscar.Locate,
 					SubGroup:  oscar.LocateUserInfoReply,
 					SubGroup:  oscar.LocateUserInfoReply,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
 				Body: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
 					TLVUserInfo: newTestSession("requested-user",
 					TLVUserInfo: newTestSession("requested-user",
@@ -197,13 +223,19 @@ func TestSendAndReceiveUserInfoQuery2(t *testing.T) {
 			name:         "request user info of user who blocked requester, expect not logged in error",
 			name:         "request user info of user who blocked requester, expect not logged in error",
 			blockedState: state.BlockedB,
 			blockedState: state.BlockedB,
 			userSession:  newTestSession("user_screen_name"),
 			userSession:  newTestSession("user_screen_name"),
-			inputSNAC: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
-				ScreenName: "requested-user",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
+					ScreenName: "requested-user",
+				},
 			},
 			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Locate,
 					FoodGroup: oscar.Locate,
 					SubGroup:  oscar.LocateErr,
 					SubGroup:  oscar.LocateErr,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNACError{
 				Body: oscar.SNACError{
 					Code: oscar.ErrorCodeNotLoggedOn,
 					Code: oscar.ErrorCodeNotLoggedOn,
@@ -222,13 +254,19 @@ func TestSendAndReceiveUserInfoQuery2(t *testing.T) {
 				},
 				},
 			},
 			},
 			userSession: newTestSession("user_screen_name"),
 			userSession: newTestSession("user_screen_name"),
-			inputSNAC: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
-				ScreenName: "non_existent_requested_user",
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
+					ScreenName: "non_existent_requested_user",
+				},
 			},
 			},
 			expectOutput: oscar.SNACMessage{
 			expectOutput: oscar.SNACMessage{
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.Locate,
 					FoodGroup: oscar.Locate,
 					SubGroup:  oscar.LocateErr,
 					SubGroup:  oscar.LocateErr,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNACError{
 				Body: oscar.SNACError{
 					Code: oscar.ErrorCodeNotLoggedOn,
 					Code: oscar.ErrorCodeNotLoggedOn,
@@ -241,7 +279,8 @@ func TestSendAndReceiveUserInfoQuery2(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			fm := newMockFeedbagManager(t)
 			fm := newMockFeedbagManager(t)
 			fm.EXPECT().
 			fm.EXPECT().
-				Blocked(tc.userSession.ScreenName(), tc.inputSNAC.ScreenName).
+				Blocked(tc.userSession.ScreenName(),
+					tc.inputSNAC.Body.(oscar.SNAC_0x02_0x15_LocateUserInfoQuery2).ScreenName).
 				Return(tc.blockedState, nil).
 				Return(tc.blockedState, nil).
 				Maybe()
 				Maybe()
 			sm := newMockSessionManager(t)
 			sm := newMockSessionManager(t)
@@ -258,13 +297,13 @@ func TestSendAndReceiveUserInfoQuery2(t *testing.T) {
 					Return(val.payload, val.err).
 					Return(val.payload, val.err).
 					Maybe()
 					Maybe()
 			}
 			}
-
 			svc := LocateService{
 			svc := LocateService{
 				sessionManager: sm,
 				sessionManager: sm,
 				feedbagManager: fm,
 				feedbagManager: fm,
 				profileManager: pm,
 				profileManager: pm,
 			}
 			}
-			outputSNAC, err := svc.UserInfoQuery2Handler(context.Background(), tc.userSession, tc.inputSNAC)
+			outputSNAC, err := svc.UserInfoQuery2Handler(context.Background(), tc.userSession, tc.inputSNAC.Frame,
+				tc.inputSNAC.Body.(oscar.SNAC_0x02_0x15_LocateUserInfoQuery2))
 			assert.NoError(t, err)
 			assert.NoError(t, err)
 			assert.Equal(t, tc.expectOutput, outputSNAC)
 			assert.Equal(t, tc.expectOutput, outputSNAC)
 		})
 		})

+ 23 - 18
handler/oservice.go

@@ -22,24 +22,26 @@ type OServiceService struct {
 	sessionManager SessionManager
 	sessionManager SessionManager
 }
 }
 
 
-func (s OServiceService) ClientVersionsHandler(_ context.Context, snacPayloadIn oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage {
+func (s OServiceService) ClientVersionsHandler(_ context.Context, frame oscar.SNACFrame, inBody oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage {
 	return oscar.SNACMessage{
 	return oscar.SNACMessage{
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.OService,
 			FoodGroup: oscar.OService,
 			SubGroup:  oscar.OServiceHostVersions,
 			SubGroup:  oscar.OServiceHostVersions,
+			RequestID: frame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x01_0x18_OServiceHostVersions{
 		Body: oscar.SNAC_0x01_0x18_OServiceHostVersions{
-			Versions: snacPayloadIn.Versions,
+			Versions: inBody.Versions,
 		},
 		},
 	}
 	}
 }
 }
 
 
-func (s OServiceService) RateParamsQueryHandler(_ context.Context) oscar.SNACMessage {
-	snacFrameOut := oscar.SNACFrame{
+func (s OServiceService) RateParamsQueryHandler(_ context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
+	frameOut := oscar.SNACFrame{
 		FoodGroup: oscar.OService,
 		FoodGroup: oscar.OService,
 		SubGroup:  oscar.OServiceRateParamsReply,
 		SubGroup:  oscar.OServiceRateParamsReply,
+		RequestID: inFrame.RequestID,
 	}
 	}
-	snacPayloadOut := oscar.SNAC_0x01_0x07_OServiceRateParamsReply{
+	bodyOut := oscar.SNAC_0x01_0x07_OServiceRateParamsReply{
 		RateClasses: []struct {
 		RateClasses: []struct {
 			ID              uint16
 			ID              uint16
 			WindowSize      uint32
 			WindowSize      uint32
@@ -84,7 +86,7 @@ func (s OServiceService) RateParamsQueryHandler(_ context.Context) oscar.SNACMes
 
 
 	for i := uint16(0); i < 24; i++ { // for each food group
 	for i := uint16(0); i < 24; i++ { // for each food group
 		for j := uint16(0); j < 32; j++ { // for each subgroup
 		for j := uint16(0); j < 32; j++ { // for each subgroup
-			snacPayloadOut.RateGroups[0].Pairs = append(snacPayloadOut.RateGroups[0].Pairs,
+			bodyOut.RateGroups[0].Pairs = append(bodyOut.RateGroups[0].Pairs,
 				struct {
 				struct {
 					FoodGroup uint16
 					FoodGroup uint16
 					SubGroup  uint16
 					SubGroup  uint16
@@ -96,16 +98,17 @@ func (s OServiceService) RateParamsQueryHandler(_ context.Context) oscar.SNACMes
 	}
 	}
 
 
 	return oscar.SNACMessage{
 	return oscar.SNACMessage{
-		Frame: snacFrameOut,
-		Body:  snacPayloadOut,
+		Frame: frameOut,
+		Body:  bodyOut,
 	}
 	}
 }
 }
 
 
-func (s OServiceService) UserInfoQueryHandler(_ context.Context, sess *state.Session) oscar.SNACMessage {
+func (s OServiceService) UserInfoQueryHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame) oscar.SNACMessage {
 	return oscar.SNACMessage{
 	return oscar.SNACMessage{
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.OService,
 			FoodGroup: oscar.OService,
 			SubGroup:  oscar.OServiceUserInfoUpdate,
 			SubGroup:  oscar.OServiceUserInfoUpdate,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
 		Body: oscar.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
 			TLVUserInfo: sess.TLVUserInfo(),
 			TLVUserInfo: sess.TLVUserInfo(),
@@ -113,8 +116,8 @@ func (s OServiceService) UserInfoQueryHandler(_ context.Context, sess *state.Ses
 	}
 	}
 }
 }
 
 
-func (s OServiceService) SetUserInfoFieldsHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error) {
-	if status, hasStatus := snacPayloadIn.GetUint32(0x06); hasStatus {
+func (s OServiceService) SetUserInfoFieldsHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error) {
+	if status, hasStatus := inBody.GetUint32(0x06); hasStatus {
 		switch status {
 		switch status {
 		case 0x000:
 		case 0x000:
 			sess.SetInvisible(false)
 			sess.SetInvisible(false)
@@ -134,6 +137,7 @@ func (s OServiceService) SetUserInfoFieldsHandler(ctx context.Context, sess *sta
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.OService,
 			FoodGroup: oscar.OService,
 			SubGroup:  oscar.OServiceUserInfoUpdate,
 			SubGroup:  oscar.OServiceUserInfoUpdate,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
 		Body: oscar.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
 			TLVUserInfo: sess.TLVUserInfo(),
 			TLVUserInfo: sess.TLVUserInfo(),
@@ -141,11 +145,11 @@ func (s OServiceService) SetUserInfoFieldsHandler(ctx context.Context, sess *sta
 	}, nil
 	}, nil
 }
 }
 
 
-func (s OServiceService) IdleNotificationHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x11_OServiceIdleNotification) error {
-	if snacPayloadIn.IdleTime == 0 {
+func (s OServiceService) IdleNotificationHandler(ctx context.Context, sess *state.Session, bodyIn oscar.SNAC_0x01_0x11_OServiceIdleNotification) error {
+	if bodyIn.IdleTime == 0 {
 		sess.SetActive()
 		sess.SetActive()
 	} else {
 	} else {
-		sess.SetIdle(time.Duration(snacPayloadIn.IdleTime) * time.Second)
+		sess.SetIdle(time.Duration(bodyIn.IdleTime) * time.Second)
 	}
 	}
 	return broadcastArrival(ctx, sess, s.sessionManager, s.feedbagManager)
 	return broadcastArrival(ctx, sess, s.sessionManager, s.feedbagManager)
 }
 }
@@ -167,12 +171,12 @@ type OServiceServiceForBOS struct {
 	cr *state.ChatRegistry
 	cr *state.ChatRegistry
 }
 }
 
 
-func (s OServiceServiceForBOS) ServiceRequestHandler(_ context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x04_OServiceServiceRequest) (oscar.SNACMessage, error) {
-	if snacPayloadIn.FoodGroup != oscar.Chat {
+func (s OServiceServiceForBOS) ServiceRequestHandler(_ context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x01_0x04_OServiceServiceRequest) (oscar.SNACMessage, error) {
+	if inBody.FoodGroup != oscar.Chat {
 		return oscar.SNACMessage{}, server.ErrUnsupportedSubGroup
 		return oscar.SNACMessage{}, server.ErrUnsupportedSubGroup
 	}
 	}
 
 
-	roomMeta, ok := snacPayloadIn.GetSlice(0x01)
+	roomMeta, ok := inBody.GetSlice(0x01)
 	if !ok {
 	if !ok {
 		return oscar.SNACMessage{}, errors.New("missing room info")
 		return oscar.SNACMessage{}, errors.New("missing room info")
 	}
 	}
@@ -192,6 +196,7 @@ func (s OServiceServiceForBOS) ServiceRequestHandler(_ context.Context, sess *st
 		Frame: oscar.SNACFrame{
 		Frame: oscar.SNACFrame{
 			FoodGroup: oscar.OService,
 			FoodGroup: oscar.OService,
 			SubGroup:  oscar.OServiceServiceResponse,
 			SubGroup:  oscar.OServiceServiceResponse,
+			RequestID: inFrame.RequestID,
 		},
 		},
 		Body: oscar.SNAC_0x01_0x05_OServiceServiceResponse{
 		Body: oscar.SNAC_0x01_0x05_OServiceServiceResponse{
 			TLVRestBlock: oscar.TLVRestBlock{
 			TLVRestBlock: oscar.TLVRestBlock{
@@ -268,7 +273,7 @@ func (s OServiceServiceForChat) WriteOServiceHostOnline() oscar.SNACMessage {
 	}
 	}
 }
 }
 
 
-func (s OServiceServiceForChat) ClientOnlineHandler(ctx context.Context, _ oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session, chatID string) error {
+func (s OServiceServiceForChat) ClientOnlineHandler(ctx context.Context, bodyIn oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session, chatID string) error {
 	room, chatSessMgr, err := s.chatRegistry.Retrieve(chatID)
 	room, chatSessMgr, err := s.chatRegistry.Retrieve(chatID)
 	if err != nil {
 	if err != nil {
 		return err
 		return err

+ 39 - 22
handler/oservice_test.go

@@ -22,7 +22,7 @@ func TestReceiveAndSendServiceRequest(t *testing.T) {
 		// info
 		// info
 		userSession *state.Session
 		userSession *state.Session
 		// inputSNAC is the SNAC sent by the sender client
 		// inputSNAC is the SNAC sent by the sender client
-		inputSNAC oscar.SNAC_0x01_0x04_OServiceServiceRequest
+		inputSNAC oscar.SNACMessage
 		// expectSNACFrame is the SNAC frame sent from the server to the recipient
 		// expectSNACFrame is the SNAC frame sent from the server to the recipient
 		// client
 		// client
 		expectOutput oscar.SNACMessage
 		expectOutput oscar.SNACMessage
@@ -32,8 +32,13 @@ func TestReceiveAndSendServiceRequest(t *testing.T) {
 		{
 		{
 			name:        "request info for ICBM service, return invalid SNAC err",
 			name:        "request info for ICBM service, return invalid SNAC err",
 			userSession: newTestSession("user_screen_name"),
 			userSession: newTestSession("user_screen_name"),
-			inputSNAC: oscar.SNAC_0x01_0x04_OServiceServiceRequest{
-				FoodGroup: oscar.ICBM,
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x01_0x04_OServiceServiceRequest{
+					FoodGroup: oscar.ICBM,
+				},
 			},
 			},
 			expectErr: server.ErrUnsupportedSubGroup,
 			expectErr: server.ErrUnsupportedSubGroup,
 		},
 		},
@@ -52,15 +57,20 @@ func TestReceiveAndSendServiceRequest(t *testing.T) {
 				Name:           "my new chat",
 				Name:           "my new chat",
 			},
 			},
 			userSession: newTestSession("user_screen_name", sessOptCannedID),
 			userSession: newTestSession("user_screen_name", sessOptCannedID),
-			inputSNAC: oscar.SNAC_0x01_0x04_OServiceServiceRequest{
-				FoodGroup: oscar.Chat,
-				TLVRestBlock: oscar.TLVRestBlock{
-					TLVList: oscar.TLVList{
-						oscar.NewTLV(0x01, oscar.SNAC_0x01_0x04_TLVRoomInfo{
-							Exchange:       8,
-							Cookie:         []byte("the-chat-cookie"),
-							InstanceNumber: 16,
-						}),
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x01_0x04_OServiceServiceRequest{
+					FoodGroup: oscar.Chat,
+					TLVRestBlock: oscar.TLVRestBlock{
+						TLVList: oscar.TLVList{
+							oscar.NewTLV(0x01, oscar.SNAC_0x01_0x04_TLVRoomInfo{
+								Exchange:       8,
+								Cookie:         []byte("the-chat-cookie"),
+								InstanceNumber: 16,
+							}),
+						},
 					},
 					},
 				},
 				},
 			},
 			},
@@ -68,6 +78,7 @@ func TestReceiveAndSendServiceRequest(t *testing.T) {
 				Frame: oscar.SNACFrame{
 				Frame: oscar.SNACFrame{
 					FoodGroup: oscar.OService,
 					FoodGroup: oscar.OService,
 					SubGroup:  oscar.OServiceServiceResponse,
 					SubGroup:  oscar.OServiceServiceResponse,
+					RequestID: 1234,
 				},
 				},
 				Body: oscar.SNAC_0x01_0x05_OServiceServiceResponse{
 				Body: oscar.SNAC_0x01_0x05_OServiceServiceResponse{
 					TLVRestBlock: oscar.TLVRestBlock{
 					TLVRestBlock: oscar.TLVRestBlock{
@@ -93,15 +104,20 @@ func TestReceiveAndSendServiceRequest(t *testing.T) {
 			},
 			},
 			chatRoom:    nil,
 			chatRoom:    nil,
 			userSession: newTestSession("user_screen_name", sessOptCannedID),
 			userSession: newTestSession("user_screen_name", sessOptCannedID),
-			inputSNAC: oscar.SNAC_0x01_0x04_OServiceServiceRequest{
-				FoodGroup: oscar.Chat,
-				TLVRestBlock: oscar.TLVRestBlock{
-					TLVList: oscar.TLVList{
-						oscar.NewTLV(0x01, oscar.SNAC_0x01_0x04_TLVRoomInfo{
-							Exchange:       8,
-							Cookie:         []byte("the-chat-cookie"),
-							InstanceNumber: 16,
-						}),
+			inputSNAC: oscar.SNACMessage{
+				Frame: oscar.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: oscar.SNAC_0x01_0x04_OServiceServiceRequest{
+					FoodGroup: oscar.Chat,
+					TLVRestBlock: oscar.TLVRestBlock{
+						TLVList: oscar.TLVList{
+							oscar.NewTLV(0x01, oscar.SNAC_0x01_0x04_TLVRoomInfo{
+								Exchange:       8,
+								Cookie:         []byte("the-chat-cookie"),
+								InstanceNumber: 16,
+							}),
+						},
 					},
 					},
 				},
 				},
 			},
 			},
@@ -134,7 +150,8 @@ func TestReceiveAndSendServiceRequest(t *testing.T) {
 				cr: cr,
 				cr: cr,
 			}
 			}
 
 
-			outputSNAC, err := svc.ServiceRequestHandler(nil, tc.userSession, tc.inputSNAC)
+			outputSNAC, err := svc.ServiceRequestHandler(nil, tc.userSession, tc.inputSNAC.Frame,
+				tc.inputSNAC.Body.(oscar.SNAC_0x01_0x04_OServiceServiceRequest))
 			assert.ErrorIs(t, err, tc.expectErr)
 			assert.ErrorIs(t, err, tc.expectErr)
 			if tc.expectErr != nil {
 			if tc.expectErr != nil {
 				return
 				return

+ 1 - 1
handler/profile_manager_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package handler
 package handler
 
 

+ 1 - 1
handler/session_manager_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package handler
 package handler
 
 

+ 1 - 1
handler/user_manager_manager_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package handler
 package handler
 
 

+ 1 - 1
oscar/snacs.go

@@ -341,7 +341,7 @@ const (
 	ICBMParameterQuery     uint16 = 0x0004
 	ICBMParameterQuery     uint16 = 0x0004
 	ICBMParameterReply     uint16 = 0x0005
 	ICBMParameterReply     uint16 = 0x0005
 	ICBMChannelMsgToHost   uint16 = 0x0006
 	ICBMChannelMsgToHost   uint16 = 0x0006
-	ICBMChannelMsgToclient uint16 = 0x0007
+	ICBMChannelMsgToClient uint16 = 0x0007
 	ICBMEvilRequest        uint16 = 0x0008
 	ICBMEvilRequest        uint16 = 0x0008
 	ICBMEvilReply          uint16 = 0x0009
 	ICBMEvilReply          uint16 = 0x0009
 	ICBMMissedCalls        uint16 = 0x000A
 	ICBMMissedCalls        uint16 = 0x000A

+ 1 - 1
oscar/snacs_string.go

@@ -115,7 +115,7 @@ var subGroupStr = map[uint16]map[uint16]string{
 		ICBMParameterQuery:     "ICBMParameterQuery",
 		ICBMParameterQuery:     "ICBMParameterQuery",
 		ICBMParameterReply:     "ICBMParameterReply",
 		ICBMParameterReply:     "ICBMParameterReply",
 		ICBMChannelMsgToHost:   "ICBMChannelMsgToHost",
 		ICBMChannelMsgToHost:   "ICBMChannelMsgToHost",
-		ICBMChannelMsgToclient: "ICBMChannelMsgToclient",
+		ICBMChannelMsgToClient: "ICBMChannelMsgToClient",
 		ICBMEvilRequest:        "ICBMEvilRequest",
 		ICBMEvilRequest:        "ICBMEvilRequest",
 		ICBMEvilReply:          "ICBMEvilReply",
 		ICBMEvilReply:          "ICBMEvilReply",
 		ICBMMissedCalls:        "ICBMMissedCalls",
 		ICBMMissedCalls:        "ICBMMissedCalls",

+ 3 - 3
server/alert.go

@@ -19,14 +19,14 @@ type AlertRouter struct {
 	RouteLogger
 	RouteLogger
 }
 }
 
 
-func (rt *AlertRouter) RouteAlert(ctx context.Context, SNACFrame oscar.SNACFrame) error {
-	switch SNACFrame.SubGroup {
+func (rt *AlertRouter) RouteAlert(ctx context.Context, inFrame oscar.SNACFrame) error {
+	switch inFrame.SubGroup {
 	case oscar.AlertNotifyCapabilities:
 	case oscar.AlertNotifyCapabilities:
 		fallthrough
 		fallthrough
 	case oscar.AlertNotifyDisplayCapabilities:
 	case oscar.AlertNotifyDisplayCapabilities:
 		// just read the request to placate the client. no need to send a
 		// just read the request to placate the client. no need to send a
 		// response.
 		// response.
-		rt.logRequest(ctx, SNACFrame, nil)
+		rt.logRequest(ctx, inFrame, nil)
 		return nil
 		return nil
 	default:
 	default:
 		return ErrUnsupportedSubGroup
 		return ErrUnsupportedSubGroup

+ 10 - 10
server/auth_service.go

@@ -13,8 +13,8 @@ import (
 )
 )
 
 
 type AuthHandler interface {
 type AuthHandler interface {
-	ReceiveAndSendAuthChallenge(snacPayloadIn oscar.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (oscar.SNACMessage, error)
-	ReceiveAndSendBUCPLoginRequest(snacPayloadIn oscar.SNAC_0x17_0x02_BUCPLoginRequest, newUUID func() uuid.UUID) (oscar.SNACMessage, error)
+	ReceiveAndSendAuthChallenge(bodyIn oscar.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (oscar.SNACMessage, error)
+	ReceiveAndSendBUCPLoginRequest(bodyIn oscar.SNAC_0x17_0x02_BUCPLoginRequest, newUUID func() uuid.UUID) (oscar.SNACMessage, error)
 	RetrieveChatSession(ctx context.Context, chatID string, sessID string) (*state.Session, error)
 	RetrieveChatSession(ctx context.Context, chatID string, sessID string) (*state.Session, error)
 	SendAndReceiveSignonFrame(rw io.ReadWriter, sequence *uint32) (oscar.FLAPSignonFrame, error)
 	SendAndReceiveSignonFrame(rw io.ReadWriter, sequence *uint32) (oscar.FLAPSignonFrame, error)
 	Signout(ctx context.Context, sess *state.Session) error
 	Signout(ctx context.Context, sess *state.Session) error
@@ -55,18 +55,18 @@ func (rt AuthService) handleAuthConnection(rwc io.ReadWriteCloser) {
 		return
 		return
 	}
 	}
 
 
-	snacPayloadIn := oscar.SNAC_0x17_0x06_BUCPChallengeRequest{}
-	if err := oscar.Unmarshal(&snacPayloadIn, buf); err != nil {
+	bodyIn := oscar.SNAC_0x17_0x06_BUCPChallengeRequest{}
+	if err := oscar.Unmarshal(&bodyIn, buf); err != nil {
 		rt.Logger.Error(err.Error())
 		rt.Logger.Error(err.Error())
 		return
 		return
 	}
 	}
 
 
-	msg, err := rt.ReceiveAndSendAuthChallenge(snacPayloadIn, uuid.New)
+	msg, err := rt.ReceiveAndSendAuthChallenge(bodyIn, uuid.New)
 	if err != nil {
 	if err != nil {
 		rt.Logger.Error(err.Error())
 		rt.Logger.Error(err.Error())
 		return
 		return
 	}
 	}
-	if err := sendSNAC(0, msg.Frame, msg.Body, &seq, rwc); err != nil {
+	if err := sendSNAC(msg.Frame, msg.Body, &seq, rwc); err != nil {
 		rt.Logger.Error(err.Error())
 		rt.Logger.Error(err.Error())
 		return
 		return
 	}
 	}
@@ -88,18 +88,18 @@ func (rt AuthService) handleAuthConnection(rwc io.ReadWriteCloser) {
 		return
 		return
 	}
 	}
 
 
-	snacPayloadIn2 := oscar.SNAC_0x17_0x02_BUCPLoginRequest{}
-	if err := oscar.Unmarshal(&snacPayloadIn2, buf); err != nil {
+	bodyIn2 := oscar.SNAC_0x17_0x02_BUCPLoginRequest{}
+	if err := oscar.Unmarshal(&bodyIn2, buf); err != nil {
 		rt.Logger.Error(err.Error())
 		rt.Logger.Error(err.Error())
 		return
 		return
 	}
 	}
 
 
-	msg, err = rt.ReceiveAndSendBUCPLoginRequest(snacPayloadIn2, uuid.New)
+	msg, err = rt.ReceiveAndSendBUCPLoginRequest(bodyIn2, uuid.New)
 	if err != nil {
 	if err != nil {
 		rt.Logger.Error(err.Error())
 		rt.Logger.Error(err.Error())
 		return
 		return
 	}
 	}
-	if err := sendSNAC(0, msg.Frame, msg.Body, &seq, rwc); err != nil {
+	if err := sendSNAC(msg.Frame, msg.Body, &seq, rwc); err != nil {
 		rt.Logger.Error(err.Error())
 		rt.Logger.Error(err.Error())
 		return
 		return
 	}
 	}

+ 14 - 14
server/bos_service.go

@@ -68,7 +68,7 @@ func (rt BOSService) handleNewConnection(ctx context.Context, rwc io.ReadWriteCl
 	ctx = context.WithValue(ctx, "screenName", sess.ScreenName())
 	ctx = context.WithValue(ctx, "screenName", sess.ScreenName())
 
 
 	msg := rt.WriteOServiceHostOnline()
 	msg := rt.WriteOServiceHostOnline()
-	if err := sendSNAC(0, msg.Frame, msg.Body, &seq, rwc); err != nil {
+	if err := sendSNAC(msg.Frame, msg.Body, &seq, rwc); err != nil {
 		rt.Logger.ErrorContext(ctx, "error WriteOServiceHostOnline")
 		rt.Logger.ErrorContext(ctx, "error WriteOServiceHostOnline")
 		return
 		return
 	}
 	}
@@ -77,44 +77,44 @@ func (rt BOSService) handleNewConnection(ctx context.Context, rwc io.ReadWriteCl
 		return rt.route(ctx, sess, r, w, seq)
 		return rt.route(ctx, sess, r, w, seq)
 	}
 	}
 	fnAlertHandler := func(ctx context.Context, msg oscar.SNACMessage, w io.Writer, seq *uint32) error {
 	fnAlertHandler := func(ctx context.Context, msg oscar.SNACMessage, w io.Writer, seq *uint32) error {
-		return sendSNAC(0, msg.Frame, msg.Body, seq, w)
+		return sendSNAC(msg.Frame, msg.Body, seq, w)
 	}
 	}
 	dispatchIncomingMessages(ctx, sess, seq, rwc, rt.Logger, fnClientReqHandler, fnAlertHandler)
 	dispatchIncomingMessages(ctx, sess, seq, rwc, rt.Logger, fnClientReqHandler, fnAlertHandler)
 }
 }
 
 
 func (rt BOSService) route(ctx context.Context, sess *state.Session, r io.Reader, w io.Writer, sequence *uint32) error {
 func (rt BOSService) route(ctx context.Context, sess *state.Session, r io.Reader, w io.Writer, sequence *uint32) error {
-	snac := oscar.SNACFrame{}
-	if err := oscar.Unmarshal(&snac, r); err != nil {
+	inFrame := oscar.SNACFrame{}
+	if err := oscar.Unmarshal(&inFrame, r); err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	err := func() error {
 	err := func() error {
-		switch snac.FoodGroup {
+		switch inFrame.FoodGroup {
 		case oscar.OService:
 		case oscar.OService:
-			return rt.RouteOService(ctx, sess, snac, r, w, sequence)
+			return rt.RouteOService(ctx, sess, inFrame, r, w, sequence)
 		case oscar.Locate:
 		case oscar.Locate:
-			return rt.RouteLocate(ctx, sess, snac, r, w, sequence)
+			return rt.RouteLocate(ctx, sess, inFrame, r, w, sequence)
 		case oscar.Buddy:
 		case oscar.Buddy:
-			return rt.RouteBuddy(ctx, snac, r, w, sequence)
+			return rt.RouteBuddy(ctx, inFrame, r, w, sequence)
 		case oscar.ICBM:
 		case oscar.ICBM:
-			return rt.RouteICBM(ctx, sess, snac, r, w, sequence)
+			return rt.RouteICBM(ctx, sess, inFrame, r, w, sequence)
 		case oscar.ChatNav:
 		case oscar.ChatNav:
-			return rt.RouteChatNav(ctx, sess, snac, r, w, sequence)
+			return rt.RouteChatNav(ctx, sess, inFrame, r, w, sequence)
 		case oscar.Feedbag:
 		case oscar.Feedbag:
-			return rt.RouteFeedbag(ctx, sess, snac, r, w, sequence)
+			return rt.RouteFeedbag(ctx, sess, inFrame, r, w, sequence)
 		case oscar.BUCP:
 		case oscar.BUCP:
 			return routeBUCP(ctx)
 			return routeBUCP(ctx)
 		case oscar.Alert:
 		case oscar.Alert:
-			return rt.RouteAlert(ctx, snac)
+			return rt.RouteAlert(ctx, inFrame)
 		default:
 		default:
 			return ErrUnsupportedSubGroup
 			return ErrUnsupportedSubGroup
 		}
 		}
 	}()
 	}()
 
 
 	if err != nil {
 	if err != nil {
-		rt.logRequestError(ctx, snac, err)
+		rt.logRequestError(ctx, inFrame, err)
 		if errors.Is(err, ErrUnsupportedSubGroup) {
 		if errors.Is(err, ErrUnsupportedSubGroup) {
-			if err1 := sendInvalidSNACErr(snac, w, sequence); err1 != nil {
+			if err1 := sendInvalidSNACErr(inFrame, w, sequence); err1 != nil {
 				err = errors.Join(err1, err)
 				err = errors.Join(err1, err)
 			}
 			}
 			if rt.Config.FailFast {
 			if rt.Config.FailFast {

+ 6 - 6
server/buddy.go

@@ -9,7 +9,7 @@ import (
 )
 )
 
 
 type BuddyHandler interface {
 type BuddyHandler interface {
-	RightsQueryHandler(ctx context.Context) oscar.SNACMessage
+	RightsQueryHandler(ctx context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage
 }
 }
 
 
 func NewBuddyRouter(logger *slog.Logger, buddyHandler BuddyHandler) BuddyRouter {
 func NewBuddyRouter(logger *slog.Logger, buddyHandler BuddyHandler) BuddyRouter {
@@ -26,16 +26,16 @@ type BuddyRouter struct {
 	RouteLogger
 	RouteLogger
 }
 }
 
 
-func (rt *BuddyRouter) RouteBuddy(ctx context.Context, SNACFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
-	switch SNACFrame.SubGroup {
+func (rt *BuddyRouter) RouteBuddy(ctx context.Context, inFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
+	switch inFrame.SubGroup {
 	case oscar.BuddyRightsQuery:
 	case oscar.BuddyRightsQuery:
 		inSNAC := oscar.SNAC_0x03_0x02_BuddyRightsQuery{}
 		inSNAC := oscar.SNAC_0x03_0x02_BuddyRightsQuery{}
 		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
 		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC := rt.RightsQueryHandler(ctx)
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		outSNAC := rt.RightsQueryHandler(ctx, inFrame)
+		rt.logRequestAndResponse(ctx, inFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	default:
 	default:
 		return ErrUnsupportedSubGroup
 		return ErrUnsupportedSubGroup
 	}
 	}

+ 12 - 11
server/buddy_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package server
 package server
 
 
@@ -22,13 +22,13 @@ func (_m *mockBuddyHandler) EXPECT() *mockBuddyHandler_Expecter {
 	return &mockBuddyHandler_Expecter{mock: &_m.Mock}
 	return &mockBuddyHandler_Expecter{mock: &_m.Mock}
 }
 }
 
 
-// RightsQueryHandler provides a mock function with given fields: ctx
-func (_m *mockBuddyHandler) RightsQueryHandler(ctx context.Context) oscar.SNACMessage {
-	ret := _m.Called(ctx)
+// RightsQueryHandler provides a mock function with given fields: ctx, inFrame
+func (_m *mockBuddyHandler) RightsQueryHandler(ctx context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
+	ret := _m.Called(ctx, inFrame)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context) oscar.SNACMessage); ok {
-		r0 = rf(ctx)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame) oscar.SNACMessage); ok {
+		r0 = rf(ctx, inFrame)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -43,13 +43,14 @@ type mockBuddyHandler_RightsQueryHandler_Call struct {
 
 
 // RightsQueryHandler is a helper method to define mock.On call
 // RightsQueryHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-func (_e *mockBuddyHandler_Expecter) RightsQueryHandler(ctx interface{}) *mockBuddyHandler_RightsQueryHandler_Call {
-	return &mockBuddyHandler_RightsQueryHandler_Call{Call: _e.mock.On("RightsQueryHandler", ctx)}
+//   - inFrame oscar.SNACFrame
+func (_e *mockBuddyHandler_Expecter) RightsQueryHandler(ctx interface{}, inFrame interface{}) *mockBuddyHandler_RightsQueryHandler_Call {
+	return &mockBuddyHandler_RightsQueryHandler_Call{Call: _e.mock.On("RightsQueryHandler", ctx, inFrame)}
 }
 }
 
 
-func (_c *mockBuddyHandler_RightsQueryHandler_Call) Run(run func(ctx context.Context)) *mockBuddyHandler_RightsQueryHandler_Call {
+func (_c *mockBuddyHandler_RightsQueryHandler_Call) Run(run func(ctx context.Context, inFrame oscar.SNACFrame)) *mockBuddyHandler_RightsQueryHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -59,7 +60,7 @@ func (_c *mockBuddyHandler_RightsQueryHandler_Call) Return(_a0 oscar.SNACMessage
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockBuddyHandler_RightsQueryHandler_Call) RunAndReturn(run func(context.Context) oscar.SNACMessage) *mockBuddyHandler_RightsQueryHandler_Call {
+func (_c *mockBuddyHandler_RightsQueryHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame) oscar.SNACMessage) *mockBuddyHandler_RightsQueryHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 0 - 128
server/buddy_test.go

@@ -1,128 +0,0 @@
-package server
-
-import (
-	"bytes"
-	"testing"
-
-	"github.com/mkaminski/goaim/oscar"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/mock"
-)
-
-func TestBuddyRouter_RouteBuddy(t *testing.T) {
-	cases := []struct {
-		// name is the unit test name
-		name string
-		// input is the request payload
-		input oscar.SNACMessage
-		// output is the response payload
-		output oscar.SNACMessage
-		// handlerErr is the mocked handler error response
-		handlerErr error
-		// expectErr is the expected error returned by the router
-		expectErr error
-	}{
-		{
-			name: "receive BuddyRightsQuery, return BuddyRightsReply",
-			input: oscar.SNACMessage{
-				Frame: oscar.SNACFrame{
-					FoodGroup: oscar.Buddy,
-					SubGroup:  oscar.BuddyRightsQuery,
-				},
-				Body: oscar.SNAC_0x03_0x02_BuddyRightsQuery{
-					TLVRestBlock: oscar.TLVRestBlock{
-						TLVList: oscar.TLVList{
-							{
-								TType: 0x01,
-								Val:   []byte{1, 2, 3, 4},
-							},
-						},
-					},
-				},
-			},
-			output: oscar.SNACMessage{
-				Frame: oscar.SNACFrame{
-					FoodGroup: oscar.Buddy,
-					SubGroup:  oscar.BuddyRightsReply,
-				},
-				Body: oscar.SNAC_0x03_0x03_BuddyRightsReply{
-					TLVRestBlock: oscar.TLVRestBlock{
-						TLVList: oscar.TLVList{
-							{
-								TType: 0x01,
-								Val:   []byte{1, 2, 3, 4},
-							},
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "receive ErrorCodeReplyTooBig, expect ErrUnsupportedSubGroup",
-			input: oscar.SNACMessage{
-				Frame: oscar.SNACFrame{
-					FoodGroup: oscar.Buddy,
-					SubGroup:  oscar.ErrorCodeReplyTooBig,
-				},
-				Body: struct{}{}, // empty SNAC
-			},
-			output:    oscar.SNACMessage{},
-			expectErr: ErrUnsupportedSubGroup,
-		},
-	}
-
-	for _, tc := range cases {
-		t.Run(tc.name, func(t *testing.T) {
-			svc := newMockBuddyHandler(t)
-			svc.EXPECT().
-				RightsQueryHandler(mock.Anything).
-				Return(tc.output).
-				Maybe()
-
-			router := BuddyRouter{
-				BuddyHandler: svc,
-				RouteLogger: RouteLogger{
-					Logger: NewLogger(Config{}),
-				},
-			}
-
-			bufIn := &bytes.Buffer{}
-			assert.NoError(t, oscar.Marshal(tc.input.Body, bufIn))
-
-			bufOut := &bytes.Buffer{}
-			seq := uint32(1)
-
-			err := router.RouteBuddy(nil, tc.input.Frame, bufIn, bufOut, &seq)
-			assert.ErrorIs(t, err, tc.expectErr)
-			if tc.expectErr != nil {
-				return
-			}
-
-			if tc.output == (oscar.SNACMessage{}) {
-				// make sure no response was sent
-				assert.Empty(t, bufOut.Bytes())
-				return
-			}
-
-			// verify the FLAP frame
-			flap := oscar.FLAPFrame{}
-			assert.NoError(t, oscar.Unmarshal(&flap, bufOut))
-
-			// make sure the sequence number was incremented
-			assert.Equal(t, uint32(2), seq)
-
-			flapBuf, err := flap.SNACBuffer(bufOut)
-			assert.NoError(t, err)
-
-			// verify the SNAC frame
-			snacFrame := oscar.SNACFrame{}
-			assert.NoError(t, oscar.Unmarshal(&snacFrame, flapBuf))
-			assert.Equal(t, tc.output.Frame, snacFrame)
-
-			// verify the SNAC message
-			snacBuf := &bytes.Buffer{}
-			assert.NoError(t, oscar.Marshal(tc.output.Body, snacBuf))
-			assert.Equal(t, snacBuf.Bytes(), flapBuf.Bytes())
-		})
-	}
-}

+ 8 - 8
server/chat.go

@@ -10,7 +10,7 @@ import (
 )
 )
 
 
 type ChatHandler interface {
 type ChatHandler interface {
-	ChannelMsgToHostHandler(ctx context.Context, sess *state.Session, chatID string, snacPayloadIn oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) (*oscar.SNACMessage, error)
+	ChannelMsgToHostHandler(ctx context.Context, sess *state.Session, chatID string, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) (*oscar.SNACMessage, error)
 }
 }
 
 
 func NewChatRouter(logger *slog.Logger, chatHandler ChatHandler) ChatRouter {
 func NewChatRouter(logger *slog.Logger, chatHandler ChatHandler) ChatRouter {
@@ -27,14 +27,14 @@ type ChatRouter struct {
 	RouteLogger
 	RouteLogger
 }
 }
 
 
-func (rt *ChatRouter) RouteChat(ctx context.Context, sess *state.Session, chatID string, SNACFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
-	switch SNACFrame.SubGroup {
+func (rt *ChatRouter) RouteChat(ctx context.Context, sess *state.Session, chatID string, inFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
+	switch inFrame.SubGroup {
 	case oscar.ChatChannelMsgToHost:
 	case oscar.ChatChannelMsgToHost:
-		inSNAC := oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC, err := rt.ChannelMsgToHostHandler(ctx, sess, chatID, inSNAC)
+		outSNAC, err := rt.ChannelMsgToHostHandler(ctx, sess, chatID, inFrame, inBody)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
@@ -42,8 +42,8 @@ func (rt *ChatRouter) RouteChat(ctx context.Context, sess *state.Session, chatID
 			return nil
 			return nil
 		}
 		}
 		rt.Logger.InfoContext(ctx, "user sent a chat message")
 		rt.Logger.InfoContext(ctx, "user sent a chat message")
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	default:
 	default:
 		return ErrUnsupportedSubGroup
 		return ErrUnsupportedSubGroup
 	}
 	}

+ 17 - 16
server/chat_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package server
 package server
 
 
@@ -24,25 +24,25 @@ func (_m *mockChatHandler) EXPECT() *mockChatHandler_Expecter {
 	return &mockChatHandler_Expecter{mock: &_m.Mock}
 	return &mockChatHandler_Expecter{mock: &_m.Mock}
 }
 }
 
 
-// ChannelMsgToHostHandler provides a mock function with given fields: ctx, sess, chatID, snacPayloadIn
-func (_m *mockChatHandler) ChannelMsgToHostHandler(ctx context.Context, sess *state.Session, chatID string, snacPayloadIn oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) (*oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess, chatID, snacPayloadIn)
+// ChannelMsgToHostHandler provides a mock function with given fields: ctx, sess, chatID, inFrame, inBody
+func (_m *mockChatHandler) ChannelMsgToHostHandler(ctx context.Context, sess *state.Session, chatID string, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) (*oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, chatID, inFrame, inBody)
 
 
 	var r0 *oscar.SNACMessage
 	var r0 *oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, string, oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) (*oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess, chatID, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, string, oscar.SNACFrame, oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) (*oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, chatID, inFrame, inBody)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, string, oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) *oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess, chatID, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, string, oscar.SNACFrame, oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) *oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, chatID, inFrame, inBody)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*oscar.SNACMessage)
 			r0 = ret.Get(0).(*oscar.SNACMessage)
 		}
 		}
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, string, oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) error); ok {
-		r1 = rf(ctx, sess, chatID, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, string, oscar.SNACFrame, oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) error); ok {
+		r1 = rf(ctx, sess, chatID, inFrame, inBody)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -59,14 +59,15 @@ type mockChatHandler_ChannelMsgToHostHandler_Call struct {
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
 //   - chatID string
 //   - chatID string
-//   - snacPayloadIn oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost
-func (_e *mockChatHandler_Expecter) ChannelMsgToHostHandler(ctx interface{}, sess interface{}, chatID interface{}, snacPayloadIn interface{}) *mockChatHandler_ChannelMsgToHostHandler_Call {
-	return &mockChatHandler_ChannelMsgToHostHandler_Call{Call: _e.mock.On("ChannelMsgToHostHandler", ctx, sess, chatID, snacPayloadIn)}
+//   - inFrame oscar.SNACFrame
+//   - inBody oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost
+func (_e *mockChatHandler_Expecter) ChannelMsgToHostHandler(ctx interface{}, sess interface{}, chatID interface{}, inFrame interface{}, inBody interface{}) *mockChatHandler_ChannelMsgToHostHandler_Call {
+	return &mockChatHandler_ChannelMsgToHostHandler_Call{Call: _e.mock.On("ChannelMsgToHostHandler", ctx, sess, chatID, inFrame, inBody)}
 }
 }
 
 
-func (_c *mockChatHandler_ChannelMsgToHostHandler_Call) Run(run func(ctx context.Context, sess *state.Session, chatID string, snacPayloadIn oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost)) *mockChatHandler_ChannelMsgToHostHandler_Call {
+func (_c *mockChatHandler_ChannelMsgToHostHandler_Call) Run(run func(ctx context.Context, sess *state.Session, chatID string, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost)) *mockChatHandler_ChannelMsgToHostHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(string), args[3].(oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(string), args[3].(oscar.SNACFrame), args[4].(oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -76,7 +77,7 @@ func (_c *mockChatHandler_ChannelMsgToHostHandler_Call) Return(_a0 *oscar.SNACMe
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockChatHandler_ChannelMsgToHostHandler_Call) RunAndReturn(run func(context.Context, *state.Session, string, oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) (*oscar.SNACMessage, error)) *mockChatHandler_ChannelMsgToHostHandler_Call {
+func (_c *mockChatHandler_ChannelMsgToHostHandler_Call) RunAndReturn(run func(context.Context, *state.Session, string, oscar.SNACFrame, oscar.SNAC_0x0E_0x05_ChatChannelMsgToHost) (*oscar.SNACMessage, error)) *mockChatHandler_ChannelMsgToHostHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 19 - 19
server/chat_nav.go

@@ -10,9 +10,9 @@ import (
 )
 )
 
 
 type ChatNavHandler interface {
 type ChatNavHandler interface {
-	CreateRoomHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (oscar.SNACMessage, error)
-	RequestChatRightsHandler(ctx context.Context) oscar.SNACMessage
-	RequestRoomInfoHandler(ctx context.Context, snacPayloadIn oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (oscar.SNACMessage, error)
+	CreateRoomHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (oscar.SNACMessage, error)
+	RequestChatRightsHandler(ctx context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage
+	RequestRoomInfoHandler(ctx context.Context, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (oscar.SNACMessage, error)
 }
 }
 
 
 func NewChatNavRouter(handler ChatNavHandler, logger *slog.Logger) ChatNavRouter {
 func NewChatNavRouter(handler ChatNavHandler, logger *slog.Logger) ChatNavRouter {
@@ -29,36 +29,36 @@ type ChatNavRouter struct {
 	RouteLogger
 	RouteLogger
 }
 }
 
 
-func (rt *ChatNavRouter) RouteChatNav(ctx context.Context, sess *state.Session, SNACFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
-	switch SNACFrame.SubGroup {
+func (rt *ChatNavRouter) RouteChatNav(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
+	switch inFrame.SubGroup {
 	case oscar.ChatNavRequestChatRights:
 	case oscar.ChatNavRequestChatRights:
-		outSNAC := rt.RequestChatRightsHandler(ctx)
-		rt.logRequestAndResponse(ctx, SNACFrame, nil, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		outSNAC := rt.RequestChatRightsHandler(ctx, inFrame)
+		rt.logRequestAndResponse(ctx, inFrame, nil, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.ChatNavRequestRoomInfo:
 	case oscar.ChatNavRequestRoomInfo:
-		inSNAC := oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC, err := rt.RequestRoomInfoHandler(ctx, inSNAC)
+		outSNAC, err := rt.RequestRoomInfoHandler(ctx, inFrame, inBody)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.ChatNavCreateRoom:
 	case oscar.ChatNavCreateRoom:
-		inSNAC := oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC, err := rt.CreateRoomHandler(ctx, sess, inSNAC)
+		outSNAC, err := rt.CreateRoomHandler(ctx, sess, inFrame, inBody)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		roomName, _ := inSNAC.GetString(oscar.ChatTLVRoomName)
+		roomName, _ := inBody.GetString(oscar.ChatTLVRoomName)
 		rt.Logger.InfoContext(ctx, "user started a chat room", slog.String("roomName", roomName))
 		rt.Logger.InfoContext(ctx, "user started a chat room", slog.String("roomName", roomName))
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	default:
 	default:
 		return ErrUnsupportedSubGroup
 		return ErrUnsupportedSubGroup
 	}
 	}

+ 44 - 41
server/chat_nav_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package server
 package server
 
 
@@ -24,23 +24,23 @@ func (_m *mockChatNavHandler) EXPECT() *mockChatNavHandler_Expecter {
 	return &mockChatNavHandler_Expecter{mock: &_m.Mock}
 	return &mockChatNavHandler_Expecter{mock: &_m.Mock}
 }
 }
 
 
-// CreateRoomHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockChatNavHandler) CreateRoomHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// CreateRoomHandler provides a mock function with given fields: ctx, sess, inFrame, inBody
+func (_m *mockChatNavHandler) CreateRoomHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, inFrame, inBody)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, inFrame, inBody)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) error); ok {
-		r1 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) error); ok {
+		r1 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -56,14 +56,15 @@ type mockChatNavHandler_CreateRoomHandler_Call struct {
 // CreateRoomHandler is a helper method to define mock.On call
 // CreateRoomHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate
-func (_e *mockChatNavHandler_Expecter) CreateRoomHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockChatNavHandler_CreateRoomHandler_Call {
-	return &mockChatNavHandler_CreateRoomHandler_Call{Call: _e.mock.On("CreateRoomHandler", ctx, sess, snacPayloadIn)}
+//   - inFrame oscar.SNACFrame
+//   - inBody oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate
+func (_e *mockChatNavHandler_Expecter) CreateRoomHandler(ctx interface{}, sess interface{}, inFrame interface{}, inBody interface{}) *mockChatNavHandler_CreateRoomHandler_Call {
+	return &mockChatNavHandler_CreateRoomHandler_Call{Call: _e.mock.On("CreateRoomHandler", ctx, sess, inFrame, inBody)}
 }
 }
 
 
-func (_c *mockChatNavHandler_CreateRoomHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate)) *mockChatNavHandler_CreateRoomHandler_Call {
+func (_c *mockChatNavHandler_CreateRoomHandler_Call) Run(run func(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate)) *mockChatNavHandler_CreateRoomHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame), args[3].(oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -73,18 +74,18 @@ func (_c *mockChatNavHandler_CreateRoomHandler_Call) Return(_a0 oscar.SNACMessag
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockChatNavHandler_CreateRoomHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (oscar.SNACMessage, error)) *mockChatNavHandler_CreateRoomHandler_Call {
+func (_c *mockChatNavHandler_CreateRoomHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (oscar.SNACMessage, error)) *mockChatNavHandler_CreateRoomHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// RequestChatRightsHandler provides a mock function with given fields: ctx
-func (_m *mockChatNavHandler) RequestChatRightsHandler(ctx context.Context) oscar.SNACMessage {
-	ret := _m.Called(ctx)
+// RequestChatRightsHandler provides a mock function with given fields: ctx, inFrame
+func (_m *mockChatNavHandler) RequestChatRightsHandler(ctx context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
+	ret := _m.Called(ctx, inFrame)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context) oscar.SNACMessage); ok {
-		r0 = rf(ctx)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame) oscar.SNACMessage); ok {
+		r0 = rf(ctx, inFrame)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -99,13 +100,14 @@ type mockChatNavHandler_RequestChatRightsHandler_Call struct {
 
 
 // RequestChatRightsHandler is a helper method to define mock.On call
 // RequestChatRightsHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-func (_e *mockChatNavHandler_Expecter) RequestChatRightsHandler(ctx interface{}) *mockChatNavHandler_RequestChatRightsHandler_Call {
-	return &mockChatNavHandler_RequestChatRightsHandler_Call{Call: _e.mock.On("RequestChatRightsHandler", ctx)}
+//   - inFrame oscar.SNACFrame
+func (_e *mockChatNavHandler_Expecter) RequestChatRightsHandler(ctx interface{}, inFrame interface{}) *mockChatNavHandler_RequestChatRightsHandler_Call {
+	return &mockChatNavHandler_RequestChatRightsHandler_Call{Call: _e.mock.On("RequestChatRightsHandler", ctx, inFrame)}
 }
 }
 
 
-func (_c *mockChatNavHandler_RequestChatRightsHandler_Call) Run(run func(ctx context.Context)) *mockChatNavHandler_RequestChatRightsHandler_Call {
+func (_c *mockChatNavHandler_RequestChatRightsHandler_Call) Run(run func(ctx context.Context, inFrame oscar.SNACFrame)) *mockChatNavHandler_RequestChatRightsHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -115,28 +117,28 @@ func (_c *mockChatNavHandler_RequestChatRightsHandler_Call) Return(_a0 oscar.SNA
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockChatNavHandler_RequestChatRightsHandler_Call) RunAndReturn(run func(context.Context) oscar.SNACMessage) *mockChatNavHandler_RequestChatRightsHandler_Call {
+func (_c *mockChatNavHandler_RequestChatRightsHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame) oscar.SNACMessage) *mockChatNavHandler_RequestChatRightsHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// RequestRoomInfoHandler provides a mock function with given fields: ctx, snacPayloadIn
-func (_m *mockChatNavHandler) RequestRoomInfoHandler(ctx context.Context, snacPayloadIn oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, snacPayloadIn)
+// RequestRoomInfoHandler provides a mock function with given fields: ctx, inFrame, inBody
+func (_m *mockChatNavHandler) RequestRoomInfoHandler(ctx context.Context, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, inFrame, inBody)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (oscar.SNACMessage, error)); ok {
-		return rf(ctx, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame, oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (oscar.SNACMessage, error)); ok {
+		return rf(ctx, inFrame, inBody)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) oscar.SNACMessage); ok {
-		r0 = rf(ctx, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame, oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) oscar.SNACMessage); ok {
+		r0 = rf(ctx, inFrame, inBody)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) error); ok {
-		r1 = rf(ctx, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, oscar.SNACFrame, oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) error); ok {
+		r1 = rf(ctx, inFrame, inBody)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -151,14 +153,15 @@ type mockChatNavHandler_RequestRoomInfoHandler_Call struct {
 
 
 // RequestRoomInfoHandler is a helper method to define mock.On call
 // RequestRoomInfoHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-//   - snacPayloadIn oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo
-func (_e *mockChatNavHandler_Expecter) RequestRoomInfoHandler(ctx interface{}, snacPayloadIn interface{}) *mockChatNavHandler_RequestRoomInfoHandler_Call {
-	return &mockChatNavHandler_RequestRoomInfoHandler_Call{Call: _e.mock.On("RequestRoomInfoHandler", ctx, snacPayloadIn)}
+//   - inFrame oscar.SNACFrame
+//   - inBody oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo
+func (_e *mockChatNavHandler_Expecter) RequestRoomInfoHandler(ctx interface{}, inFrame interface{}, inBody interface{}) *mockChatNavHandler_RequestRoomInfoHandler_Call {
+	return &mockChatNavHandler_RequestRoomInfoHandler_Call{Call: _e.mock.On("RequestRoomInfoHandler", ctx, inFrame, inBody)}
 }
 }
 
 
-func (_c *mockChatNavHandler_RequestRoomInfoHandler_Call) Run(run func(ctx context.Context, snacPayloadIn oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo)) *mockChatNavHandler_RequestRoomInfoHandler_Call {
+func (_c *mockChatNavHandler_RequestRoomInfoHandler_Call) Run(run func(ctx context.Context, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo)) *mockChatNavHandler_RequestRoomInfoHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame), args[2].(oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -168,7 +171,7 @@ func (_c *mockChatNavHandler_RequestRoomInfoHandler_Call) Return(_a0 oscar.SNACM
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockChatNavHandler_RequestRoomInfoHandler_Call) RunAndReturn(run func(context.Context, oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (oscar.SNACMessage, error)) *mockChatNavHandler_RequestRoomInfoHandler_Call {
+func (_c *mockChatNavHandler_RequestRoomInfoHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame, oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (oscar.SNACMessage, error)) *mockChatNavHandler_RequestRoomInfoHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 3 - 3
server/chat_nav_test.go

@@ -113,15 +113,15 @@ func TestChatNavRouter_RouteChatNavRouter(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			svc := newMockChatNavHandler(t)
 			svc := newMockChatNavHandler(t)
 			svc.EXPECT().
 			svc.EXPECT().
-				RequestChatRightsHandler(mock.Anything).
+				RequestChatRightsHandler(mock.Anything, tc.input.Frame).
 				Return(tc.output).
 				Return(tc.output).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				RequestRoomInfoHandler(mock.Anything, tc.input.Body).
+				RequestRoomInfoHandler(mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output, tc.handlerErr).
 				Return(tc.output, tc.handlerErr).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				CreateRoomHandler(mock.Anything, mock.Anything, tc.input.Body).
+				CreateRoomHandler(mock.Anything, mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output, tc.handlerErr).
 				Return(tc.output, tc.handlerErr).
 				Maybe()
 				Maybe()
 
 

+ 9 - 9
server/chat_service.go

@@ -70,7 +70,7 @@ func (rt ChatService) handleNewConnection(ctx context.Context, rw io.ReadWriter)
 	ctx = context.WithValue(ctx, "screenName", chatSess.ScreenName())
 	ctx = context.WithValue(ctx, "screenName", chatSess.ScreenName())
 
 
 	msg := rt.WriteOServiceHostOnline()
 	msg := rt.WriteOServiceHostOnline()
-	if err := sendSNAC(0, msg.Frame, msg.Body, &seq, rw); err != nil {
+	if err := sendSNAC(msg.Frame, msg.Body, &seq, rw); err != nil {
 		rt.Logger.ErrorContext(ctx, "error WriteOServiceHostOnline")
 		rt.Logger.ErrorContext(ctx, "error WriteOServiceHostOnline")
 		return
 		return
 	}
 	}
@@ -79,32 +79,32 @@ func (rt ChatService) handleNewConnection(ctx context.Context, rw io.ReadWriter)
 		return rt.route(ctx, chatSess, r, w, seq, chatID)
 		return rt.route(ctx, chatSess, r, w, seq, chatID)
 	}
 	}
 	fnAlertHandler := func(ctx context.Context, msg oscar.SNACMessage, w io.Writer, seq *uint32) error {
 	fnAlertHandler := func(ctx context.Context, msg oscar.SNACMessage, w io.Writer, seq *uint32) error {
-		return sendSNAC(0, msg.Frame, msg.Body, seq, w)
+		return sendSNAC(msg.Frame, msg.Body, seq, w)
 	}
 	}
 	dispatchIncomingMessages(ctx, chatSess, seq, rw, rt.Logger, fnClientReqHandler, fnAlertHandler)
 	dispatchIncomingMessages(ctx, chatSess, seq, rw, rt.Logger, fnClientReqHandler, fnAlertHandler)
 }
 }
 
 
 func (rt ChatService) route(ctx context.Context, sess *state.Session, r io.Reader, w io.Writer, sequence *uint32, chatID string) error {
 func (rt ChatService) route(ctx context.Context, sess *state.Session, r io.Reader, w io.Writer, sequence *uint32, chatID string) error {
-	snac := oscar.SNACFrame{}
-	if err := oscar.Unmarshal(&snac, r); err != nil {
+	inFrame := oscar.SNACFrame{}
+	if err := oscar.Unmarshal(&inFrame, r); err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	err := func() error {
 	err := func() error {
-		switch snac.FoodGroup {
+		switch inFrame.FoodGroup {
 		case oscar.OService:
 		case oscar.OService:
-			return rt.RouteOService(ctx, sess, chatID, snac, r, w, sequence)
+			return rt.RouteOService(ctx, sess, chatID, inFrame, r, w, sequence)
 		case oscar.Chat:
 		case oscar.Chat:
-			return rt.RouteChat(ctx, sess, chatID, snac, r, w, sequence)
+			return rt.RouteChat(ctx, sess, chatID, inFrame, r, w, sequence)
 		default:
 		default:
 			return ErrUnsupportedSubGroup
 			return ErrUnsupportedSubGroup
 		}
 		}
 	}()
 	}()
 
 
 	if err != nil {
 	if err != nil {
-		rt.logRequestError(ctx, snac, err)
+		rt.logRequestError(ctx, inFrame, err)
 		if errors.Is(err, ErrUnsupportedSubGroup) {
 		if errors.Is(err, ErrUnsupportedSubGroup) {
-			if err1 := sendInvalidSNACErr(snac, w, sequence); err1 != nil {
+			if err1 := sendInvalidSNACErr(inFrame, w, sequence); err1 != nil {
 				err = errors.Join(err1, err)
 				err = errors.Join(err1, err)
 			}
 			}
 			if rt.Config.FailFast {
 			if rt.Config.FailFast {

+ 1 - 1
server/chat_test.go

@@ -74,7 +74,7 @@ func TestChatRouter_RouteChat(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			svc := newMockChatHandler(t)
 			svc := newMockChatHandler(t)
 			svc.EXPECT().
 			svc.EXPECT().
-				ChannelMsgToHostHandler(mock.Anything, mock.Anything, mock.Anything, tc.input.Body).
+				ChannelMsgToHostHandler(mock.Anything, mock.Anything, mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output, tc.handlerErr).
 				Return(tc.output, tc.handlerErr).
 				Maybe()
 				Maybe()
 
 

+ 7 - 8
server/connection.go

@@ -24,9 +24,7 @@ type (
 	clientReqHandler func(ctx context.Context, r io.Reader, w io.Writer, u *uint32) error
 	clientReqHandler func(ctx context.Context, r io.Reader, w io.Writer, u *uint32) error
 )
 )
 
 
-func sendSNAC(requestID uint32, frame oscar.SNACFrame, body any, sequence *uint32, w io.Writer) error {
-	frame.RequestID = requestID
-
+func sendSNAC(frame oscar.SNACFrame, body any, sequence *uint32, w io.Writer) error {
 	snacBuf := &bytes.Buffer{}
 	snacBuf := &bytes.Buffer{}
 	if err := oscar.Marshal(frame, snacBuf); err != nil {
 	if err := oscar.Marshal(frame, snacBuf); err != nil {
 		return err
 		return err
@@ -59,15 +57,16 @@ func sendSNAC(requestID uint32, frame oscar.SNACFrame, body any, sequence *uint3
 	return nil
 	return nil
 }
 }
 
 
-func sendInvalidSNACErr(frame oscar.SNACFrame, w io.Writer, sequence *uint32) error {
-	snacFrameOut := oscar.SNACFrame{
-		FoodGroup: frame.FoodGroup,
+func sendInvalidSNACErr(frameIn oscar.SNACFrame, w io.Writer, sequence *uint32) error {
+	frameOut := oscar.SNACFrame{
+		FoodGroup: frameIn.FoodGroup,
 		SubGroup:  0x01, // error subgroup for all SNACs
 		SubGroup:  0x01, // error subgroup for all SNACs
+		RequestID: frameIn.RequestID,
 	}
 	}
-	snacPayloadOut := oscar.SNACError{
+	bodyOut := oscar.SNACError{
 		Code: oscar.ErrorCodeInvalidSnac,
 		Code: oscar.ErrorCodeInvalidSnac,
 	}
 	}
-	return sendSNAC(frame.RequestID, snacFrameOut, snacPayloadOut, sequence, w)
+	return sendSNAC(frameOut, bodyOut, sequence, w)
 }
 }
 
 
 func consumeFLAPFrames(r io.Reader, msgCh chan incomingMessage, errCh chan error) {
 func consumeFLAPFrames(r io.Reader, msgCh chan incomingMessage, errCh chan error) {

+ 43 - 43
server/feedbag.go

@@ -10,13 +10,13 @@ import (
 )
 )
 
 
 type FeedbagHandler interface {
 type FeedbagHandler interface {
-	DeleteItemHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) (oscar.SNACMessage, error)
-	InsertItemHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x08_FeedbagInsertItem) (oscar.SNACMessage, error)
-	QueryHandler(ctx context.Context, sess *state.Session) (oscar.SNACMessage, error)
-	QueryIfModifiedHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) (oscar.SNACMessage, error)
-	RightsQueryHandler(context.Context) oscar.SNACMessage
-	StartClusterHandler(context.Context, oscar.SNAC_0x13_0x11_FeedbagStartCluster)
-	UpdateItemHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x09_FeedbagUpdateItem) (oscar.SNACMessage, error)
+	DeleteItemHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) (oscar.SNACMessage, error)
+	InsertItemHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x08_FeedbagInsertItem) (oscar.SNACMessage, error)
+	QueryHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame) (oscar.SNACMessage, error)
+	QueryIfModifiedHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) (oscar.SNACMessage, error)
+	RightsQueryHandler(ctx context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage
+	StartClusterHandler(ctx context.Context, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x11_FeedbagStartCluster)
+	UpdateItemHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x09_FeedbagUpdateItem) (oscar.SNACMessage, error)
 }
 }
 
 
 func NewFeedbagRouter(logger *slog.Logger, handler FeedbagHandler) FeedbagRouter {
 func NewFeedbagRouter(logger *slog.Logger, handler FeedbagHandler) FeedbagRouter {
@@ -33,80 +33,80 @@ type FeedbagRouter struct {
 	RouteLogger
 	RouteLogger
 }
 }
 
 
-func (rt FeedbagRouter) RouteFeedbag(ctx context.Context, sess *state.Session, SNACFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
-	switch SNACFrame.SubGroup {
+func (rt FeedbagRouter) RouteFeedbag(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
+	switch inFrame.SubGroup {
 	case oscar.FeedbagRightsQuery:
 	case oscar.FeedbagRightsQuery:
-		inSNAC := oscar.SNAC_0x13_0x02_FeedbagRightsQuery{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x13_0x02_FeedbagRightsQuery{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC := rt.RightsQueryHandler(ctx)
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		outSNAC := rt.RightsQueryHandler(ctx, inFrame)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.FeedbagQuery:
 	case oscar.FeedbagQuery:
-		inSNAC, err := rt.QueryHandler(ctx, sess)
+		outSNAC, err := rt.QueryHandler(ctx, sess, inFrame)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		rt.logRequest(ctx, SNACFrame, inSNAC)
-		return sendSNAC(SNACFrame.RequestID, inSNAC.Frame, inSNAC.Body, sequence, w)
+		rt.logRequest(ctx, inFrame, outSNAC)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.FeedbagQueryIfModified:
 	case oscar.FeedbagQueryIfModified:
-		inSNAC := oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC, err := rt.QueryIfModifiedHandler(ctx, sess, inSNAC)
+		outSNAC, err := rt.QueryIfModifiedHandler(ctx, sess, inFrame, inBody)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.FeedbagUse:
 	case oscar.FeedbagUse:
-		rt.logRequest(ctx, SNACFrame, nil)
+		rt.logRequest(ctx, inFrame, nil)
 		return nil
 		return nil
 	case oscar.FeedbagInsertItem:
 	case oscar.FeedbagInsertItem:
-		inSNAC := oscar.SNAC_0x13_0x08_FeedbagInsertItem{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x13_0x08_FeedbagInsertItem{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC, err := rt.InsertItemHandler(ctx, sess, inSNAC)
+		outSNAC, err := rt.InsertItemHandler(ctx, sess, inFrame, inBody)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.FeedbagUpdateItem:
 	case oscar.FeedbagUpdateItem:
-		inSNAC := oscar.SNAC_0x13_0x09_FeedbagUpdateItem{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x13_0x09_FeedbagUpdateItem{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC, err := rt.UpdateItemHandler(ctx, sess, inSNAC)
+		outSNAC, err := rt.UpdateItemHandler(ctx, sess, inFrame, inBody)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.FeedbagDeleteItem:
 	case oscar.FeedbagDeleteItem:
-		inSNAC := oscar.SNAC_0x13_0x0A_FeedbagDeleteItem{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x13_0x0A_FeedbagDeleteItem{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC, err := rt.DeleteItemHandler(ctx, sess, inSNAC)
+		outSNAC, err := rt.DeleteItemHandler(ctx, sess, inFrame, inBody)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.FeedbagStartCluster:
 	case oscar.FeedbagStartCluster:
-		inSNAC := oscar.SNAC_0x13_0x11_FeedbagStartCluster{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x13_0x11_FeedbagStartCluster{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		rt.StartClusterHandler(ctx, inSNAC)
-		rt.logRequest(ctx, SNACFrame, inSNAC)
+		rt.StartClusterHandler(ctx, inFrame, inBody)
+		rt.logRequest(ctx, inFrame, inBody)
 		return nil
 		return nil
 	case oscar.FeedbagEndCluster:
 	case oscar.FeedbagEndCluster:
-		rt.logRequest(ctx, SNACFrame, nil)
+		rt.logRequest(ctx, inFrame, nil)
 		return nil
 		return nil
 	default:
 	default:
 		return ErrUnsupportedSubGroup
 		return ErrUnsupportedSubGroup

+ 103 - 96
server/feedbag_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package server
 package server
 
 
@@ -24,23 +24,23 @@ func (_m *mockFeedbagHandler) EXPECT() *mockFeedbagHandler_Expecter {
 	return &mockFeedbagHandler_Expecter{mock: &_m.Mock}
 	return &mockFeedbagHandler_Expecter{mock: &_m.Mock}
 }
 }
 
 
-// DeleteItemHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockFeedbagHandler) DeleteItemHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) (oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// DeleteItemHandler provides a mock function with given fields: ctx, sess, inFrame, inBody
+func (_m *mockFeedbagHandler) DeleteItemHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) (oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, inFrame, inBody)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) (oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) (oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, inFrame, inBody)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) error); ok {
-		r1 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) error); ok {
+		r1 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -56,14 +56,15 @@ type mockFeedbagHandler_DeleteItemHandler_Call struct {
 // DeleteItemHandler is a helper method to define mock.On call
 // DeleteItemHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x13_0x0A_FeedbagDeleteItem
-func (_e *mockFeedbagHandler_Expecter) DeleteItemHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockFeedbagHandler_DeleteItemHandler_Call {
-	return &mockFeedbagHandler_DeleteItemHandler_Call{Call: _e.mock.On("DeleteItemHandler", ctx, sess, snacPayloadIn)}
+//   - inFrame oscar.SNACFrame
+//   - inBody oscar.SNAC_0x13_0x0A_FeedbagDeleteItem
+func (_e *mockFeedbagHandler_Expecter) DeleteItemHandler(ctx interface{}, sess interface{}, inFrame interface{}, inBody interface{}) *mockFeedbagHandler_DeleteItemHandler_Call {
+	return &mockFeedbagHandler_DeleteItemHandler_Call{Call: _e.mock.On("DeleteItemHandler", ctx, sess, inFrame, inBody)}
 }
 }
 
 
-func (_c *mockFeedbagHandler_DeleteItemHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x0A_FeedbagDeleteItem)) *mockFeedbagHandler_DeleteItemHandler_Call {
+func (_c *mockFeedbagHandler_DeleteItemHandler_Call) Run(run func(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x0A_FeedbagDeleteItem)) *mockFeedbagHandler_DeleteItemHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x13_0x0A_FeedbagDeleteItem))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame), args[3].(oscar.SNAC_0x13_0x0A_FeedbagDeleteItem))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -73,28 +74,28 @@ func (_c *mockFeedbagHandler_DeleteItemHandler_Call) Return(_a0 oscar.SNACMessag
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagHandler_DeleteItemHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) (oscar.SNACMessage, error)) *mockFeedbagHandler_DeleteItemHandler_Call {
+func (_c *mockFeedbagHandler_DeleteItemHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x0A_FeedbagDeleteItem) (oscar.SNACMessage, error)) *mockFeedbagHandler_DeleteItemHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// InsertItemHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockFeedbagHandler) InsertItemHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x08_FeedbagInsertItem) (oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// InsertItemHandler provides a mock function with given fields: ctx, sess, inFrame, inBody
+func (_m *mockFeedbagHandler) InsertItemHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x08_FeedbagInsertItem) (oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, inFrame, inBody)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x13_0x08_FeedbagInsertItem) (oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x08_FeedbagInsertItem) (oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, inFrame, inBody)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x13_0x08_FeedbagInsertItem) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x08_FeedbagInsertItem) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNAC_0x13_0x08_FeedbagInsertItem) error); ok {
-		r1 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x08_FeedbagInsertItem) error); ok {
+		r1 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -110,14 +111,15 @@ type mockFeedbagHandler_InsertItemHandler_Call struct {
 // InsertItemHandler is a helper method to define mock.On call
 // InsertItemHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x13_0x08_FeedbagInsertItem
-func (_e *mockFeedbagHandler_Expecter) InsertItemHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockFeedbagHandler_InsertItemHandler_Call {
-	return &mockFeedbagHandler_InsertItemHandler_Call{Call: _e.mock.On("InsertItemHandler", ctx, sess, snacPayloadIn)}
+//   - inFrame oscar.SNACFrame
+//   - inBody oscar.SNAC_0x13_0x08_FeedbagInsertItem
+func (_e *mockFeedbagHandler_Expecter) InsertItemHandler(ctx interface{}, sess interface{}, inFrame interface{}, inBody interface{}) *mockFeedbagHandler_InsertItemHandler_Call {
+	return &mockFeedbagHandler_InsertItemHandler_Call{Call: _e.mock.On("InsertItemHandler", ctx, sess, inFrame, inBody)}
 }
 }
 
 
-func (_c *mockFeedbagHandler_InsertItemHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x08_FeedbagInsertItem)) *mockFeedbagHandler_InsertItemHandler_Call {
+func (_c *mockFeedbagHandler_InsertItemHandler_Call) Run(run func(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x08_FeedbagInsertItem)) *mockFeedbagHandler_InsertItemHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x13_0x08_FeedbagInsertItem))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame), args[3].(oscar.SNAC_0x13_0x08_FeedbagInsertItem))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -127,28 +129,28 @@ func (_c *mockFeedbagHandler_InsertItemHandler_Call) Return(_a0 oscar.SNACMessag
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagHandler_InsertItemHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNAC_0x13_0x08_FeedbagInsertItem) (oscar.SNACMessage, error)) *mockFeedbagHandler_InsertItemHandler_Call {
+func (_c *mockFeedbagHandler_InsertItemHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x08_FeedbagInsertItem) (oscar.SNACMessage, error)) *mockFeedbagHandler_InsertItemHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// QueryHandler provides a mock function with given fields: ctx, sess
-func (_m *mockFeedbagHandler) QueryHandler(ctx context.Context, sess *state.Session) (oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess)
+// QueryHandler provides a mock function with given fields: ctx, sess, inFrame
+func (_m *mockFeedbagHandler) QueryHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame) (oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, inFrame)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session) (oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame) (oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, inFrame)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, inFrame)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session) error); ok {
-		r1 = rf(ctx, sess)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNACFrame) error); ok {
+		r1 = rf(ctx, sess, inFrame)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -164,13 +166,14 @@ type mockFeedbagHandler_QueryHandler_Call struct {
 // QueryHandler is a helper method to define mock.On call
 // QueryHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-func (_e *mockFeedbagHandler_Expecter) QueryHandler(ctx interface{}, sess interface{}) *mockFeedbagHandler_QueryHandler_Call {
-	return &mockFeedbagHandler_QueryHandler_Call{Call: _e.mock.On("QueryHandler", ctx, sess)}
+//   - inFrame oscar.SNACFrame
+func (_e *mockFeedbagHandler_Expecter) QueryHandler(ctx interface{}, sess interface{}, inFrame interface{}) *mockFeedbagHandler_QueryHandler_Call {
+	return &mockFeedbagHandler_QueryHandler_Call{Call: _e.mock.On("QueryHandler", ctx, sess, inFrame)}
 }
 }
 
 
-func (_c *mockFeedbagHandler_QueryHandler_Call) Run(run func(ctx context.Context, sess *state.Session)) *mockFeedbagHandler_QueryHandler_Call {
+func (_c *mockFeedbagHandler_QueryHandler_Call) Run(run func(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame)) *mockFeedbagHandler_QueryHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -180,28 +183,28 @@ func (_c *mockFeedbagHandler_QueryHandler_Call) Return(_a0 oscar.SNACMessage, _a
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagHandler_QueryHandler_Call) RunAndReturn(run func(context.Context, *state.Session) (oscar.SNACMessage, error)) *mockFeedbagHandler_QueryHandler_Call {
+func (_c *mockFeedbagHandler_QueryHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame) (oscar.SNACMessage, error)) *mockFeedbagHandler_QueryHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// QueryIfModifiedHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockFeedbagHandler) QueryIfModifiedHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) (oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// QueryIfModifiedHandler provides a mock function with given fields: ctx, sess, inFrame, inBody
+func (_m *mockFeedbagHandler) QueryIfModifiedHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) (oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, inFrame, inBody)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) (oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) (oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, inFrame, inBody)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) error); ok {
-		r1 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) error); ok {
+		r1 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -217,14 +220,15 @@ type mockFeedbagHandler_QueryIfModifiedHandler_Call struct {
 // QueryIfModifiedHandler is a helper method to define mock.On call
 // QueryIfModifiedHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x13_0x05_FeedbagQueryIfModified
-func (_e *mockFeedbagHandler_Expecter) QueryIfModifiedHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockFeedbagHandler_QueryIfModifiedHandler_Call {
-	return &mockFeedbagHandler_QueryIfModifiedHandler_Call{Call: _e.mock.On("QueryIfModifiedHandler", ctx, sess, snacPayloadIn)}
+//   - inFrame oscar.SNACFrame
+//   - inBody oscar.SNAC_0x13_0x05_FeedbagQueryIfModified
+func (_e *mockFeedbagHandler_Expecter) QueryIfModifiedHandler(ctx interface{}, sess interface{}, inFrame interface{}, inBody interface{}) *mockFeedbagHandler_QueryIfModifiedHandler_Call {
+	return &mockFeedbagHandler_QueryIfModifiedHandler_Call{Call: _e.mock.On("QueryIfModifiedHandler", ctx, sess, inFrame, inBody)}
 }
 }
 
 
-func (_c *mockFeedbagHandler_QueryIfModifiedHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x05_FeedbagQueryIfModified)) *mockFeedbagHandler_QueryIfModifiedHandler_Call {
+func (_c *mockFeedbagHandler_QueryIfModifiedHandler_Call) Run(run func(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x05_FeedbagQueryIfModified)) *mockFeedbagHandler_QueryIfModifiedHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x13_0x05_FeedbagQueryIfModified))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame), args[3].(oscar.SNAC_0x13_0x05_FeedbagQueryIfModified))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -234,18 +238,18 @@ func (_c *mockFeedbagHandler_QueryIfModifiedHandler_Call) Return(_a0 oscar.SNACM
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagHandler_QueryIfModifiedHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) (oscar.SNACMessage, error)) *mockFeedbagHandler_QueryIfModifiedHandler_Call {
+func (_c *mockFeedbagHandler_QueryIfModifiedHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x05_FeedbagQueryIfModified) (oscar.SNACMessage, error)) *mockFeedbagHandler_QueryIfModifiedHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// RightsQueryHandler provides a mock function with given fields: _a0
-func (_m *mockFeedbagHandler) RightsQueryHandler(_a0 context.Context) oscar.SNACMessage {
-	ret := _m.Called(_a0)
+// RightsQueryHandler provides a mock function with given fields: ctx, inFrame
+func (_m *mockFeedbagHandler) RightsQueryHandler(ctx context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
+	ret := _m.Called(ctx, inFrame)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context) oscar.SNACMessage); ok {
-		r0 = rf(_a0)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame) oscar.SNACMessage); ok {
+		r0 = rf(ctx, inFrame)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -259,14 +263,15 @@ type mockFeedbagHandler_RightsQueryHandler_Call struct {
 }
 }
 
 
 // RightsQueryHandler is a helper method to define mock.On call
 // RightsQueryHandler is a helper method to define mock.On call
-//   - _a0 context.Context
-func (_e *mockFeedbagHandler_Expecter) RightsQueryHandler(_a0 interface{}) *mockFeedbagHandler_RightsQueryHandler_Call {
-	return &mockFeedbagHandler_RightsQueryHandler_Call{Call: _e.mock.On("RightsQueryHandler", _a0)}
+//   - ctx context.Context
+//   - inFrame oscar.SNACFrame
+func (_e *mockFeedbagHandler_Expecter) RightsQueryHandler(ctx interface{}, inFrame interface{}) *mockFeedbagHandler_RightsQueryHandler_Call {
+	return &mockFeedbagHandler_RightsQueryHandler_Call{Call: _e.mock.On("RightsQueryHandler", ctx, inFrame)}
 }
 }
 
 
-func (_c *mockFeedbagHandler_RightsQueryHandler_Call) Run(run func(_a0 context.Context)) *mockFeedbagHandler_RightsQueryHandler_Call {
+func (_c *mockFeedbagHandler_RightsQueryHandler_Call) Run(run func(ctx context.Context, inFrame oscar.SNACFrame)) *mockFeedbagHandler_RightsQueryHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -276,14 +281,14 @@ func (_c *mockFeedbagHandler_RightsQueryHandler_Call) Return(_a0 oscar.SNACMessa
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagHandler_RightsQueryHandler_Call) RunAndReturn(run func(context.Context) oscar.SNACMessage) *mockFeedbagHandler_RightsQueryHandler_Call {
+func (_c *mockFeedbagHandler_RightsQueryHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame) oscar.SNACMessage) *mockFeedbagHandler_RightsQueryHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// StartClusterHandler provides a mock function with given fields: _a0, _a1
-func (_m *mockFeedbagHandler) StartClusterHandler(_a0 context.Context, _a1 oscar.SNAC_0x13_0x11_FeedbagStartCluster) {
-	_m.Called(_a0, _a1)
+// StartClusterHandler provides a mock function with given fields: ctx, inFrame, inBody
+func (_m *mockFeedbagHandler) StartClusterHandler(ctx context.Context, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x11_FeedbagStartCluster) {
+	_m.Called(ctx, inFrame, inBody)
 }
 }
 
 
 // mockFeedbagHandler_StartClusterHandler_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StartClusterHandler'
 // mockFeedbagHandler_StartClusterHandler_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StartClusterHandler'
@@ -292,15 +297,16 @@ type mockFeedbagHandler_StartClusterHandler_Call struct {
 }
 }
 
 
 // StartClusterHandler is a helper method to define mock.On call
 // StartClusterHandler is a helper method to define mock.On call
-//   - _a0 context.Context
-//   - _a1 oscar.SNAC_0x13_0x11_FeedbagStartCluster
-func (_e *mockFeedbagHandler_Expecter) StartClusterHandler(_a0 interface{}, _a1 interface{}) *mockFeedbagHandler_StartClusterHandler_Call {
-	return &mockFeedbagHandler_StartClusterHandler_Call{Call: _e.mock.On("StartClusterHandler", _a0, _a1)}
+//   - ctx context.Context
+//   - inFrame oscar.SNACFrame
+//   - inBody oscar.SNAC_0x13_0x11_FeedbagStartCluster
+func (_e *mockFeedbagHandler_Expecter) StartClusterHandler(ctx interface{}, inFrame interface{}, inBody interface{}) *mockFeedbagHandler_StartClusterHandler_Call {
+	return &mockFeedbagHandler_StartClusterHandler_Call{Call: _e.mock.On("StartClusterHandler", ctx, inFrame, inBody)}
 }
 }
 
 
-func (_c *mockFeedbagHandler_StartClusterHandler_Call) Run(run func(_a0 context.Context, _a1 oscar.SNAC_0x13_0x11_FeedbagStartCluster)) *mockFeedbagHandler_StartClusterHandler_Call {
+func (_c *mockFeedbagHandler_StartClusterHandler_Call) Run(run func(ctx context.Context, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x11_FeedbagStartCluster)) *mockFeedbagHandler_StartClusterHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(oscar.SNAC_0x13_0x11_FeedbagStartCluster))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame), args[2].(oscar.SNAC_0x13_0x11_FeedbagStartCluster))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -310,28 +316,28 @@ func (_c *mockFeedbagHandler_StartClusterHandler_Call) Return() *mockFeedbagHand
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagHandler_StartClusterHandler_Call) RunAndReturn(run func(context.Context, oscar.SNAC_0x13_0x11_FeedbagStartCluster)) *mockFeedbagHandler_StartClusterHandler_Call {
+func (_c *mockFeedbagHandler_StartClusterHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame, oscar.SNAC_0x13_0x11_FeedbagStartCluster)) *mockFeedbagHandler_StartClusterHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// UpdateItemHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockFeedbagHandler) UpdateItemHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x09_FeedbagUpdateItem) (oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// UpdateItemHandler provides a mock function with given fields: ctx, sess, inFrame, inBody
+func (_m *mockFeedbagHandler) UpdateItemHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x09_FeedbagUpdateItem) (oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, inFrame, inBody)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x13_0x09_FeedbagUpdateItem) (oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x09_FeedbagUpdateItem) (oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, inFrame, inBody)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x13_0x09_FeedbagUpdateItem) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x09_FeedbagUpdateItem) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNAC_0x13_0x09_FeedbagUpdateItem) error); ok {
-		r1 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x09_FeedbagUpdateItem) error); ok {
+		r1 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -347,14 +353,15 @@ type mockFeedbagHandler_UpdateItemHandler_Call struct {
 // UpdateItemHandler is a helper method to define mock.On call
 // UpdateItemHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x13_0x09_FeedbagUpdateItem
-func (_e *mockFeedbagHandler_Expecter) UpdateItemHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockFeedbagHandler_UpdateItemHandler_Call {
-	return &mockFeedbagHandler_UpdateItemHandler_Call{Call: _e.mock.On("UpdateItemHandler", ctx, sess, snacPayloadIn)}
+//   - inFrame oscar.SNACFrame
+//   - inBody oscar.SNAC_0x13_0x09_FeedbagUpdateItem
+func (_e *mockFeedbagHandler_Expecter) UpdateItemHandler(ctx interface{}, sess interface{}, inFrame interface{}, inBody interface{}) *mockFeedbagHandler_UpdateItemHandler_Call {
+	return &mockFeedbagHandler_UpdateItemHandler_Call{Call: _e.mock.On("UpdateItemHandler", ctx, sess, inFrame, inBody)}
 }
 }
 
 
-func (_c *mockFeedbagHandler_UpdateItemHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x13_0x09_FeedbagUpdateItem)) *mockFeedbagHandler_UpdateItemHandler_Call {
+func (_c *mockFeedbagHandler_UpdateItemHandler_Call) Run(run func(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x13_0x09_FeedbagUpdateItem)) *mockFeedbagHandler_UpdateItemHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x13_0x09_FeedbagUpdateItem))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame), args[3].(oscar.SNAC_0x13_0x09_FeedbagUpdateItem))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -364,7 +371,7 @@ func (_c *mockFeedbagHandler_UpdateItemHandler_Call) Return(_a0 oscar.SNACMessag
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagHandler_UpdateItemHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNAC_0x13_0x09_FeedbagUpdateItem) (oscar.SNACMessage, error)) *mockFeedbagHandler_UpdateItemHandler_Call {
+func (_c *mockFeedbagHandler_UpdateItemHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x13_0x09_FeedbagUpdateItem) (oscar.SNACMessage, error)) *mockFeedbagHandler_UpdateItemHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 7 - 7
server/feedbag_test.go

@@ -241,31 +241,31 @@ func TestFeedbagRouter_RouteFeedbag(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			svc := newMockFeedbagHandler(t)
 			svc := newMockFeedbagHandler(t)
 			svc.EXPECT().
 			svc.EXPECT().
-				DeleteItemHandler(mock.Anything, mock.Anything, tc.input.Body).
+				DeleteItemHandler(mock.Anything, mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output, tc.handlerErr).
 				Return(tc.output, tc.handlerErr).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				QueryHandler(mock.Anything, mock.Anything).
+				QueryHandler(mock.Anything, mock.Anything, tc.input.Frame).
 				Return(tc.output, tc.handlerErr).
 				Return(tc.output, tc.handlerErr).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				QueryIfModifiedHandler(mock.Anything, mock.Anything, tc.input.Body).
+				QueryIfModifiedHandler(mock.Anything, mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output, tc.handlerErr).
 				Return(tc.output, tc.handlerErr).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				RightsQueryHandler(mock.Anything).
+				RightsQueryHandler(mock.Anything, tc.input.Frame).
 				Return(tc.output).
 				Return(tc.output).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				InsertItemHandler(mock.Anything, mock.Anything, tc.input.Body).
+				InsertItemHandler(mock.Anything, mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output, tc.handlerErr).
 				Return(tc.output, tc.handlerErr).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				UpdateItemHandler(mock.Anything, mock.Anything, tc.input.Body).
+				UpdateItemHandler(mock.Anything, mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output, tc.handlerErr).
 				Return(tc.output, tc.handlerErr).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				StartClusterHandler(mock.Anything, tc.input.Body).
+				StartClusterHandler(mock.Anything, tc.input.Frame, tc.input.Body).
 				Maybe()
 				Maybe()
 
 
 			router := FeedbagRouter{
 			router := FeedbagRouter{

+ 30 - 30
server/icbm.go

@@ -10,10 +10,10 @@ import (
 )
 )
 
 
 type ICBMHandler interface {
 type ICBMHandler interface {
-	ChannelMsgToHostHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) (*oscar.SNACMessage, error)
-	ClientEventHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x04_0x14_ICBMClientEvent) error
-	EvilRequestHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x04_0x08_ICBMEvilRequest) (oscar.SNACMessage, error)
-	ParameterQueryHandler(context.Context) oscar.SNACMessage
+	ChannelMsgToHostHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) (*oscar.SNACMessage, error)
+	ClientEventHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x04_0x14_ICBMClientEvent) error
+	EvilRequestHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x04_0x08_ICBMEvilRequest) (oscar.SNACMessage, error)
+	ParameterQueryHandler(ctx context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage
 }
 }
 
 
 func NewICBMRouter(logger *slog.Logger, handler ICBMHandler) ICBMRouter {
 func NewICBMRouter(logger *slog.Logger, handler ICBMHandler) ICBMRouter {
@@ -30,53 +30,53 @@ type ICBMRouter struct {
 	RouteLogger
 	RouteLogger
 }
 }
 
 
-func (rt *ICBMRouter) RouteICBM(ctx context.Context, sess *state.Session, SNACFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
-	switch SNACFrame.SubGroup {
+func (rt *ICBMRouter) RouteICBM(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
+	switch inFrame.SubGroup {
 	case oscar.ICBMAddParameters:
 	case oscar.ICBMAddParameters:
-		inSNAC := oscar.SNAC_0x04_0x02_ICBMAddParameters{}
-		rt.logRequest(ctx, SNACFrame, inSNAC)
-		return oscar.Unmarshal(&inSNAC, r)
+		inBody := oscar.SNAC_0x04_0x02_ICBMAddParameters{}
+		rt.logRequest(ctx, inFrame, inBody)
+		return oscar.Unmarshal(&inBody, r)
 	case oscar.ICBMParameterQuery:
 	case oscar.ICBMParameterQuery:
-		outSNAC := rt.ParameterQueryHandler(ctx)
-		rt.logRequestAndResponse(ctx, SNACFrame, outSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		outSNAC := rt.ParameterQueryHandler(ctx, inFrame)
+		rt.logRequestAndResponse(ctx, inFrame, outSNAC, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.ICBMChannelMsgToHost:
 	case oscar.ICBMChannelMsgToHost:
-		inSNAC := oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC, err := rt.ChannelMsgToHostHandler(ctx, sess, inSNAC)
+		outSNAC, err := rt.ChannelMsgToHostHandler(ctx, sess, inFrame, inBody)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		rt.Logger.InfoContext(ctx, "user sent an IM", slog.String("recipient", inSNAC.ScreenName))
+		rt.Logger.InfoContext(ctx, "user sent an IM", slog.String("recipient", inBody.ScreenName))
 		if outSNAC == nil {
 		if outSNAC == nil {
 			return nil
 			return nil
 		}
 		}
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.ICBMEvilRequest:
 	case oscar.ICBMEvilRequest:
-		inSNAC := oscar.SNAC_0x04_0x08_ICBMEvilRequest{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x04_0x08_ICBMEvilRequest{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC, err := rt.EvilRequestHandler(ctx, sess, inSNAC)
+		outSNAC, err := rt.EvilRequestHandler(ctx, sess, inFrame, inBody)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.ICBMClientErr:
 	case oscar.ICBMClientErr:
-		inSNAC := oscar.SNAC_0x04_0x0B_ICBMClientErr{}
-		rt.logRequest(ctx, SNACFrame, inSNAC)
-		return oscar.Unmarshal(&inSNAC, r)
+		inBody := oscar.SNAC_0x04_0x0B_ICBMClientErr{}
+		rt.logRequest(ctx, inFrame, inBody)
+		return oscar.Unmarshal(&inBody, r)
 	case oscar.ICBMClientEvent:
 	case oscar.ICBMClientEvent:
-		inSNAC := oscar.SNAC_0x04_0x14_ICBMClientEvent{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x04_0x14_ICBMClientEvent{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		rt.logRequest(ctx, SNACFrame, inSNAC)
-		return rt.ClientEventHandler(ctx, sess, inSNAC)
+		rt.logRequest(ctx, inFrame, inBody)
+		return rt.ClientEventHandler(ctx, sess, inFrame, inBody)
 	default:
 	default:
 		return ErrUnsupportedSubGroup
 		return ErrUnsupportedSubGroup
 	}
 	}

+ 57 - 53
server/icbm_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package server
 package server
 
 
@@ -24,25 +24,25 @@ func (_m *mockICBMHandler) EXPECT() *mockICBMHandler_Expecter {
 	return &mockICBMHandler_Expecter{mock: &_m.Mock}
 	return &mockICBMHandler_Expecter{mock: &_m.Mock}
 }
 }
 
 
-// ChannelMsgToHostHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockICBMHandler) ChannelMsgToHostHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) (*oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// ChannelMsgToHostHandler provides a mock function with given fields: ctx, sess, inFrame, inBody
+func (_m *mockICBMHandler) ChannelMsgToHostHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) (*oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, inFrame, inBody)
 
 
 	var r0 *oscar.SNACMessage
 	var r0 *oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) (*oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) (*oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, inFrame, inBody)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) *oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) *oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*oscar.SNACMessage)
 			r0 = ret.Get(0).(*oscar.SNACMessage)
 		}
 		}
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) error); ok {
-		r1 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) error); ok {
+		r1 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -58,14 +58,15 @@ type mockICBMHandler_ChannelMsgToHostHandler_Call struct {
 // ChannelMsgToHostHandler is a helper method to define mock.On call
 // ChannelMsgToHostHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost
-func (_e *mockICBMHandler_Expecter) ChannelMsgToHostHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockICBMHandler_ChannelMsgToHostHandler_Call {
-	return &mockICBMHandler_ChannelMsgToHostHandler_Call{Call: _e.mock.On("ChannelMsgToHostHandler", ctx, sess, snacPayloadIn)}
+//   - inFrame oscar.SNACFrame
+//   - inBody oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost
+func (_e *mockICBMHandler_Expecter) ChannelMsgToHostHandler(ctx interface{}, sess interface{}, inFrame interface{}, inBody interface{}) *mockICBMHandler_ChannelMsgToHostHandler_Call {
+	return &mockICBMHandler_ChannelMsgToHostHandler_Call{Call: _e.mock.On("ChannelMsgToHostHandler", ctx, sess, inFrame, inBody)}
 }
 }
 
 
-func (_c *mockICBMHandler_ChannelMsgToHostHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost)) *mockICBMHandler_ChannelMsgToHostHandler_Call {
+func (_c *mockICBMHandler_ChannelMsgToHostHandler_Call) Run(run func(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost)) *mockICBMHandler_ChannelMsgToHostHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame), args[3].(oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -75,18 +76,18 @@ func (_c *mockICBMHandler_ChannelMsgToHostHandler_Call) Return(_a0 *oscar.SNACMe
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockICBMHandler_ChannelMsgToHostHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) (*oscar.SNACMessage, error)) *mockICBMHandler_ChannelMsgToHostHandler_Call {
+func (_c *mockICBMHandler_ChannelMsgToHostHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost) (*oscar.SNACMessage, error)) *mockICBMHandler_ChannelMsgToHostHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// ClientEventHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockICBMHandler) ClientEventHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x04_0x14_ICBMClientEvent) error {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// ClientEventHandler provides a mock function with given fields: ctx, sess, inFrame, inBody
+func (_m *mockICBMHandler) ClientEventHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x04_0x14_ICBMClientEvent) error {
+	ret := _m.Called(ctx, sess, inFrame, inBody)
 
 
 	var r0 error
 	var r0 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x04_0x14_ICBMClientEvent) error); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x04_0x14_ICBMClientEvent) error); ok {
+		r0 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r0 = ret.Error(0)
 		r0 = ret.Error(0)
 	}
 	}
@@ -102,14 +103,15 @@ type mockICBMHandler_ClientEventHandler_Call struct {
 // ClientEventHandler is a helper method to define mock.On call
 // ClientEventHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x04_0x14_ICBMClientEvent
-func (_e *mockICBMHandler_Expecter) ClientEventHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockICBMHandler_ClientEventHandler_Call {
-	return &mockICBMHandler_ClientEventHandler_Call{Call: _e.mock.On("ClientEventHandler", ctx, sess, snacPayloadIn)}
+//   - inFrame oscar.SNACFrame
+//   - inBody oscar.SNAC_0x04_0x14_ICBMClientEvent
+func (_e *mockICBMHandler_Expecter) ClientEventHandler(ctx interface{}, sess interface{}, inFrame interface{}, inBody interface{}) *mockICBMHandler_ClientEventHandler_Call {
+	return &mockICBMHandler_ClientEventHandler_Call{Call: _e.mock.On("ClientEventHandler", ctx, sess, inFrame, inBody)}
 }
 }
 
 
-func (_c *mockICBMHandler_ClientEventHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x04_0x14_ICBMClientEvent)) *mockICBMHandler_ClientEventHandler_Call {
+func (_c *mockICBMHandler_ClientEventHandler_Call) Run(run func(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x04_0x14_ICBMClientEvent)) *mockICBMHandler_ClientEventHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x04_0x14_ICBMClientEvent))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame), args[3].(oscar.SNAC_0x04_0x14_ICBMClientEvent))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -119,28 +121,28 @@ func (_c *mockICBMHandler_ClientEventHandler_Call) Return(_a0 error) *mockICBMHa
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockICBMHandler_ClientEventHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNAC_0x04_0x14_ICBMClientEvent) error) *mockICBMHandler_ClientEventHandler_Call {
+func (_c *mockICBMHandler_ClientEventHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x04_0x14_ICBMClientEvent) error) *mockICBMHandler_ClientEventHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// EvilRequestHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockICBMHandler) EvilRequestHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x04_0x08_ICBMEvilRequest) (oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// EvilRequestHandler provides a mock function with given fields: ctx, sess, inFrame, inBody
+func (_m *mockICBMHandler) EvilRequestHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x04_0x08_ICBMEvilRequest) (oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, inFrame, inBody)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x04_0x08_ICBMEvilRequest) (oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x04_0x08_ICBMEvilRequest) (oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, inFrame, inBody)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x04_0x08_ICBMEvilRequest) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x04_0x08_ICBMEvilRequest) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNAC_0x04_0x08_ICBMEvilRequest) error); ok {
-		r1 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x04_0x08_ICBMEvilRequest) error); ok {
+		r1 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -156,14 +158,15 @@ type mockICBMHandler_EvilRequestHandler_Call struct {
 // EvilRequestHandler is a helper method to define mock.On call
 // EvilRequestHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x04_0x08_ICBMEvilRequest
-func (_e *mockICBMHandler_Expecter) EvilRequestHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockICBMHandler_EvilRequestHandler_Call {
-	return &mockICBMHandler_EvilRequestHandler_Call{Call: _e.mock.On("EvilRequestHandler", ctx, sess, snacPayloadIn)}
+//   - inFrame oscar.SNACFrame
+//   - inBody oscar.SNAC_0x04_0x08_ICBMEvilRequest
+func (_e *mockICBMHandler_Expecter) EvilRequestHandler(ctx interface{}, sess interface{}, inFrame interface{}, inBody interface{}) *mockICBMHandler_EvilRequestHandler_Call {
+	return &mockICBMHandler_EvilRequestHandler_Call{Call: _e.mock.On("EvilRequestHandler", ctx, sess, inFrame, inBody)}
 }
 }
 
 
-func (_c *mockICBMHandler_EvilRequestHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x04_0x08_ICBMEvilRequest)) *mockICBMHandler_EvilRequestHandler_Call {
+func (_c *mockICBMHandler_EvilRequestHandler_Call) Run(run func(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x04_0x08_ICBMEvilRequest)) *mockICBMHandler_EvilRequestHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x04_0x08_ICBMEvilRequest))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame), args[3].(oscar.SNAC_0x04_0x08_ICBMEvilRequest))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -173,18 +176,18 @@ func (_c *mockICBMHandler_EvilRequestHandler_Call) Return(_a0 oscar.SNACMessage,
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockICBMHandler_EvilRequestHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNAC_0x04_0x08_ICBMEvilRequest) (oscar.SNACMessage, error)) *mockICBMHandler_EvilRequestHandler_Call {
+func (_c *mockICBMHandler_EvilRequestHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x04_0x08_ICBMEvilRequest) (oscar.SNACMessage, error)) *mockICBMHandler_EvilRequestHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// ParameterQueryHandler provides a mock function with given fields: _a0
-func (_m *mockICBMHandler) ParameterQueryHandler(_a0 context.Context) oscar.SNACMessage {
-	ret := _m.Called(_a0)
+// ParameterQueryHandler provides a mock function with given fields: ctx, inFrame
+func (_m *mockICBMHandler) ParameterQueryHandler(ctx context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
+	ret := _m.Called(ctx, inFrame)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context) oscar.SNACMessage); ok {
-		r0 = rf(_a0)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame) oscar.SNACMessage); ok {
+		r0 = rf(ctx, inFrame)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -198,14 +201,15 @@ type mockICBMHandler_ParameterQueryHandler_Call struct {
 }
 }
 
 
 // ParameterQueryHandler is a helper method to define mock.On call
 // ParameterQueryHandler is a helper method to define mock.On call
-//   - _a0 context.Context
-func (_e *mockICBMHandler_Expecter) ParameterQueryHandler(_a0 interface{}) *mockICBMHandler_ParameterQueryHandler_Call {
-	return &mockICBMHandler_ParameterQueryHandler_Call{Call: _e.mock.On("ParameterQueryHandler", _a0)}
+//   - ctx context.Context
+//   - inFrame oscar.SNACFrame
+func (_e *mockICBMHandler_Expecter) ParameterQueryHandler(ctx interface{}, inFrame interface{}) *mockICBMHandler_ParameterQueryHandler_Call {
+	return &mockICBMHandler_ParameterQueryHandler_Call{Call: _e.mock.On("ParameterQueryHandler", ctx, inFrame)}
 }
 }
 
 
-func (_c *mockICBMHandler_ParameterQueryHandler_Call) Run(run func(_a0 context.Context)) *mockICBMHandler_ParameterQueryHandler_Call {
+func (_c *mockICBMHandler_ParameterQueryHandler_Call) Run(run func(ctx context.Context, inFrame oscar.SNACFrame)) *mockICBMHandler_ParameterQueryHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -215,7 +219,7 @@ func (_c *mockICBMHandler_ParameterQueryHandler_Call) Return(_a0 oscar.SNACMessa
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockICBMHandler_ParameterQueryHandler_Call) RunAndReturn(run func(context.Context) oscar.SNACMessage) *mockICBMHandler_ParameterQueryHandler_Call {
+func (_c *mockICBMHandler_ParameterQueryHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame) oscar.SNACMessage) *mockICBMHandler_ParameterQueryHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 4 - 4
server/icbm_test.go

@@ -153,20 +153,20 @@ func TestICBMRouter_RouteICBM(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			svc := newMockICBMHandler(t)
 			svc := newMockICBMHandler(t)
 			svc.EXPECT().
 			svc.EXPECT().
-				ChannelMsgToHostHandler(mock.Anything, mock.Anything, tc.input.Body).
+				ChannelMsgToHostHandler(mock.Anything, mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output, tc.handlerErr).
 				Return(tc.output, tc.handlerErr).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				ClientEventHandler(mock.Anything, mock.Anything, tc.input.Body).
+				ClientEventHandler(mock.Anything, mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.handlerErr).
 				Return(tc.handlerErr).
 				Maybe()
 				Maybe()
 			if tc.output != nil {
 			if tc.output != nil {
 				svc.EXPECT().
 				svc.EXPECT().
-					EvilRequestHandler(mock.Anything, mock.Anything, tc.input.Body).
+					EvilRequestHandler(mock.Anything, mock.Anything, tc.input.Frame, tc.input.Body).
 					Return(*tc.output, tc.handlerErr).
 					Return(*tc.output, tc.handlerErr).
 					Maybe()
 					Maybe()
 				svc.EXPECT().
 				svc.EXPECT().
-					ParameterQueryHandler(mock.Anything).
+					ParameterQueryHandler(mock.Anything, tc.input.Frame).
 					Return(*tc.output).
 					Return(*tc.output).
 					Maybe()
 					Maybe()
 			}
 			}

+ 30 - 30
server/locate.go

@@ -10,11 +10,11 @@ import (
 )
 )
 
 
 type LocateHandler interface {
 type LocateHandler interface {
-	RightsQueryHandler(ctx context.Context) oscar.SNACMessage
+	RightsQueryHandler(ctx context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage
 	SetDirInfoHandler(ctx context.Context) oscar.SNACMessage
 	SetDirInfoHandler(ctx context.Context) oscar.SNACMessage
-	SetInfoHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x02_0x04_LocateSetInfo) error
-	SetKeywordInfoHandler(ctx context.Context) oscar.SNACMessage
-	UserInfoQuery2Handler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) (oscar.SNACMessage, error)
+	SetInfoHandler(ctx context.Context, sess *state.Session, inBody oscar.SNAC_0x02_0x04_LocateSetInfo) error
+	SetKeywordInfoHandler(ctx context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage
+	UserInfoQuery2Handler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) (oscar.SNACMessage, error)
 }
 }
 
 
 func NewLocateRouter(handler LocateHandler, logger *slog.Logger) LocateRouter {
 func NewLocateRouter(handler LocateHandler, logger *slog.Logger) LocateRouter {
@@ -31,50 +31,50 @@ type LocateRouter struct {
 	RouteLogger
 	RouteLogger
 }
 }
 
 
-func (rt LocateRouter) RouteLocate(ctx context.Context, sess *state.Session, SNACFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
-	switch SNACFrame.SubGroup {
+func (rt LocateRouter) RouteLocate(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
+	switch inFrame.SubGroup {
 	case oscar.LocateRightsQuery:
 	case oscar.LocateRightsQuery:
-		outSNAC := rt.RightsQueryHandler(ctx)
-		rt.logRequestAndResponse(ctx, SNACFrame, nil, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		outSNAC := rt.RightsQueryHandler(ctx, inFrame)
+		rt.logRequestAndResponse(ctx, inFrame, nil, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.LocateSetInfo:
 	case oscar.LocateSetInfo:
-		inSNAC := oscar.SNAC_0x02_0x04_LocateSetInfo{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x02_0x04_LocateSetInfo{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		rt.logRequest(ctx, SNACFrame, inSNAC)
-		return rt.SetInfoHandler(ctx, sess, inSNAC)
+		rt.logRequest(ctx, inFrame, inBody)
+		return rt.SetInfoHandler(ctx, sess, inBody)
 	case oscar.LocateSetDirInfo:
 	case oscar.LocateSetDirInfo:
-		inSNAC := oscar.SNAC_0x02_0x09_LocateSetDirInfo{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x02_0x09_LocateSetDirInfo{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
 		outSNAC := rt.SetDirInfoHandler(ctx)
 		outSNAC := rt.SetDirInfoHandler(ctx)
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.LocateGetDirInfo:
 	case oscar.LocateGetDirInfo:
-		inSNAC := oscar.SNAC_0x02_0x0B_LocateGetDirInfo{}
-		rt.logRequest(ctx, SNACFrame, inSNAC)
-		return oscar.Unmarshal(&inSNAC, r)
+		inBody := oscar.SNAC_0x02_0x0B_LocateGetDirInfo{}
+		rt.logRequest(ctx, inFrame, inBody)
+		return oscar.Unmarshal(&inBody, r)
 	case oscar.LocateSetKeywordInfo:
 	case oscar.LocateSetKeywordInfo:
-		inSNAC := oscar.SNAC_0x02_0x0F_LocateSetKeywordInfo{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x02_0x0F_LocateSetKeywordInfo{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC := rt.SetKeywordInfoHandler(ctx)
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		outSNAC := rt.SetKeywordInfoHandler(ctx, inFrame)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.LocateUserInfoQuery2:
 	case oscar.LocateUserInfoQuery2:
-		inSNAC := oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC, err := rt.UserInfoQuery2Handler(ctx, sess, inSNAC)
+		outSNAC, err := rt.UserInfoQuery2Handler(ctx, sess, inFrame, inBody)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	default:
 	default:
 		return ErrUnsupportedSubGroup
 		return ErrUnsupportedSubGroup
 	}
 	}

+ 47 - 44
server/locate_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package server
 package server
 
 
@@ -24,13 +24,13 @@ func (_m *mockLocateHandler) EXPECT() *mockLocateHandler_Expecter {
 	return &mockLocateHandler_Expecter{mock: &_m.Mock}
 	return &mockLocateHandler_Expecter{mock: &_m.Mock}
 }
 }
 
 
-// RightsQueryHandler provides a mock function with given fields: ctx
-func (_m *mockLocateHandler) RightsQueryHandler(ctx context.Context) oscar.SNACMessage {
-	ret := _m.Called(ctx)
+// RightsQueryHandler provides a mock function with given fields: ctx, inFrame
+func (_m *mockLocateHandler) RightsQueryHandler(ctx context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
+	ret := _m.Called(ctx, inFrame)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context) oscar.SNACMessage); ok {
-		r0 = rf(ctx)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame) oscar.SNACMessage); ok {
+		r0 = rf(ctx, inFrame)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -45,13 +45,14 @@ type mockLocateHandler_RightsQueryHandler_Call struct {
 
 
 // RightsQueryHandler is a helper method to define mock.On call
 // RightsQueryHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-func (_e *mockLocateHandler_Expecter) RightsQueryHandler(ctx interface{}) *mockLocateHandler_RightsQueryHandler_Call {
-	return &mockLocateHandler_RightsQueryHandler_Call{Call: _e.mock.On("RightsQueryHandler", ctx)}
+//   - inFrame oscar.SNACFrame
+func (_e *mockLocateHandler_Expecter) RightsQueryHandler(ctx interface{}, inFrame interface{}) *mockLocateHandler_RightsQueryHandler_Call {
+	return &mockLocateHandler_RightsQueryHandler_Call{Call: _e.mock.On("RightsQueryHandler", ctx, inFrame)}
 }
 }
 
 
-func (_c *mockLocateHandler_RightsQueryHandler_Call) Run(run func(ctx context.Context)) *mockLocateHandler_RightsQueryHandler_Call {
+func (_c *mockLocateHandler_RightsQueryHandler_Call) Run(run func(ctx context.Context, inFrame oscar.SNACFrame)) *mockLocateHandler_RightsQueryHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -61,7 +62,7 @@ func (_c *mockLocateHandler_RightsQueryHandler_Call) Return(_a0 oscar.SNACMessag
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockLocateHandler_RightsQueryHandler_Call) RunAndReturn(run func(context.Context) oscar.SNACMessage) *mockLocateHandler_RightsQueryHandler_Call {
+func (_c *mockLocateHandler_RightsQueryHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame) oscar.SNACMessage) *mockLocateHandler_RightsQueryHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
@@ -108,13 +109,13 @@ func (_c *mockLocateHandler_SetDirInfoHandler_Call) RunAndReturn(run func(contex
 	return _c
 	return _c
 }
 }
 
 
-// SetInfoHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockLocateHandler) SetInfoHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x02_0x04_LocateSetInfo) error {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// SetInfoHandler provides a mock function with given fields: ctx, sess, inBody
+func (_m *mockLocateHandler) SetInfoHandler(ctx context.Context, sess *state.Session, inBody oscar.SNAC_0x02_0x04_LocateSetInfo) error {
+	ret := _m.Called(ctx, sess, inBody)
 
 
 	var r0 error
 	var r0 error
 	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x02_0x04_LocateSetInfo) error); ok {
 	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x02_0x04_LocateSetInfo) error); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+		r0 = rf(ctx, sess, inBody)
 	} else {
 	} else {
 		r0 = ret.Error(0)
 		r0 = ret.Error(0)
 	}
 	}
@@ -130,12 +131,12 @@ type mockLocateHandler_SetInfoHandler_Call struct {
 // SetInfoHandler is a helper method to define mock.On call
 // SetInfoHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x02_0x04_LocateSetInfo
-func (_e *mockLocateHandler_Expecter) SetInfoHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockLocateHandler_SetInfoHandler_Call {
-	return &mockLocateHandler_SetInfoHandler_Call{Call: _e.mock.On("SetInfoHandler", ctx, sess, snacPayloadIn)}
+//   - inBody oscar.SNAC_0x02_0x04_LocateSetInfo
+func (_e *mockLocateHandler_Expecter) SetInfoHandler(ctx interface{}, sess interface{}, inBody interface{}) *mockLocateHandler_SetInfoHandler_Call {
+	return &mockLocateHandler_SetInfoHandler_Call{Call: _e.mock.On("SetInfoHandler", ctx, sess, inBody)}
 }
 }
 
 
-func (_c *mockLocateHandler_SetInfoHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x02_0x04_LocateSetInfo)) *mockLocateHandler_SetInfoHandler_Call {
+func (_c *mockLocateHandler_SetInfoHandler_Call) Run(run func(ctx context.Context, sess *state.Session, inBody oscar.SNAC_0x02_0x04_LocateSetInfo)) *mockLocateHandler_SetInfoHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
 		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x02_0x04_LocateSetInfo))
 		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x02_0x04_LocateSetInfo))
 	})
 	})
@@ -152,13 +153,13 @@ func (_c *mockLocateHandler_SetInfoHandler_Call) RunAndReturn(run func(context.C
 	return _c
 	return _c
 }
 }
 
 
-// SetKeywordInfoHandler provides a mock function with given fields: ctx
-func (_m *mockLocateHandler) SetKeywordInfoHandler(ctx context.Context) oscar.SNACMessage {
-	ret := _m.Called(ctx)
+// SetKeywordInfoHandler provides a mock function with given fields: ctx, inFrame
+func (_m *mockLocateHandler) SetKeywordInfoHandler(ctx context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
+	ret := _m.Called(ctx, inFrame)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context) oscar.SNACMessage); ok {
-		r0 = rf(ctx)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame) oscar.SNACMessage); ok {
+		r0 = rf(ctx, inFrame)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -173,13 +174,14 @@ type mockLocateHandler_SetKeywordInfoHandler_Call struct {
 
 
 // SetKeywordInfoHandler is a helper method to define mock.On call
 // SetKeywordInfoHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-func (_e *mockLocateHandler_Expecter) SetKeywordInfoHandler(ctx interface{}) *mockLocateHandler_SetKeywordInfoHandler_Call {
-	return &mockLocateHandler_SetKeywordInfoHandler_Call{Call: _e.mock.On("SetKeywordInfoHandler", ctx)}
+//   - inFrame oscar.SNACFrame
+func (_e *mockLocateHandler_Expecter) SetKeywordInfoHandler(ctx interface{}, inFrame interface{}) *mockLocateHandler_SetKeywordInfoHandler_Call {
+	return &mockLocateHandler_SetKeywordInfoHandler_Call{Call: _e.mock.On("SetKeywordInfoHandler", ctx, inFrame)}
 }
 }
 
 
-func (_c *mockLocateHandler_SetKeywordInfoHandler_Call) Run(run func(ctx context.Context)) *mockLocateHandler_SetKeywordInfoHandler_Call {
+func (_c *mockLocateHandler_SetKeywordInfoHandler_Call) Run(run func(ctx context.Context, inFrame oscar.SNACFrame)) *mockLocateHandler_SetKeywordInfoHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -189,28 +191,28 @@ func (_c *mockLocateHandler_SetKeywordInfoHandler_Call) Return(_a0 oscar.SNACMes
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockLocateHandler_SetKeywordInfoHandler_Call) RunAndReturn(run func(context.Context) oscar.SNACMessage) *mockLocateHandler_SetKeywordInfoHandler_Call {
+func (_c *mockLocateHandler_SetKeywordInfoHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame) oscar.SNACMessage) *mockLocateHandler_SetKeywordInfoHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// UserInfoQuery2Handler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockLocateHandler) UserInfoQuery2Handler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) (oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// UserInfoQuery2Handler provides a mock function with given fields: ctx, sess, inFrame, inBody
+func (_m *mockLocateHandler) UserInfoQuery2Handler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) (oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, inFrame, inBody)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) (oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) (oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, inFrame, inBody)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) error); ok {
-		r1 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) error); ok {
+		r1 = rf(ctx, sess, inFrame, inBody)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -226,14 +228,15 @@ type mockLocateHandler_UserInfoQuery2Handler_Call struct {
 // UserInfoQuery2Handler is a helper method to define mock.On call
 // UserInfoQuery2Handler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x02_0x15_LocateUserInfoQuery2
-func (_e *mockLocateHandler_Expecter) UserInfoQuery2Handler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockLocateHandler_UserInfoQuery2Handler_Call {
-	return &mockLocateHandler_UserInfoQuery2Handler_Call{Call: _e.mock.On("UserInfoQuery2Handler", ctx, sess, snacPayloadIn)}
+//   - inFrame oscar.SNACFrame
+//   - inBody oscar.SNAC_0x02_0x15_LocateUserInfoQuery2
+func (_e *mockLocateHandler_Expecter) UserInfoQuery2Handler(ctx interface{}, sess interface{}, inFrame interface{}, inBody interface{}) *mockLocateHandler_UserInfoQuery2Handler_Call {
+	return &mockLocateHandler_UserInfoQuery2Handler_Call{Call: _e.mock.On("UserInfoQuery2Handler", ctx, sess, inFrame, inBody)}
 }
 }
 
 
-func (_c *mockLocateHandler_UserInfoQuery2Handler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x02_0x15_LocateUserInfoQuery2)) *mockLocateHandler_UserInfoQuery2Handler_Call {
+func (_c *mockLocateHandler_UserInfoQuery2Handler_Call) Run(run func(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x02_0x15_LocateUserInfoQuery2)) *mockLocateHandler_UserInfoQuery2Handler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x02_0x15_LocateUserInfoQuery2))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame), args[3].(oscar.SNAC_0x02_0x15_LocateUserInfoQuery2))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -243,7 +246,7 @@ func (_c *mockLocateHandler_UserInfoQuery2Handler_Call) Return(_a0 oscar.SNACMes
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockLocateHandler_UserInfoQuery2Handler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) (oscar.SNACMessage, error)) *mockLocateHandler_UserInfoQuery2Handler_Call {
+func (_c *mockLocateHandler_UserInfoQuery2Handler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x02_0x15_LocateUserInfoQuery2) (oscar.SNACMessage, error)) *mockLocateHandler_UserInfoQuery2Handler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 3 - 3
server/locate_test.go

@@ -187,7 +187,7 @@ func TestLocateRouter_RouteLocate(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			svc := newMockLocateHandler(t)
 			svc := newMockLocateHandler(t)
 			svc.EXPECT().
 			svc.EXPECT().
-				RightsQueryHandler(mock.Anything).
+				RightsQueryHandler(mock.Anything, tc.input.Frame).
 				Return(tc.output).
 				Return(tc.output).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
@@ -199,11 +199,11 @@ func TestLocateRouter_RouteLocate(t *testing.T) {
 				Return(tc.handlerErr).
 				Return(tc.handlerErr).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				SetKeywordInfoHandler(mock.Anything).
+				SetKeywordInfoHandler(mock.Anything, tc.input.Frame).
 				Return(tc.output).
 				Return(tc.output).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				UserInfoQuery2Handler(mock.Anything, mock.Anything, tc.input.Body).
+				UserInfoQuery2Handler(mock.Anything, mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output, tc.handlerErr).
 				Return(tc.output, tc.handlerErr).
 				Maybe()
 				Maybe()
 
 

+ 56 - 56
server/oservice.go

@@ -11,25 +11,25 @@ import (
 )
 )
 
 
 type OServiceHandler interface {
 type OServiceHandler interface {
-	ClientVersionsHandler(ctx context.Context, snacPayloadIn oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage
-	IdleNotificationHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x11_OServiceIdleNotification) error
-	RateParamsQueryHandler(ctx context.Context) oscar.SNACMessage
+	ClientVersionsHandler(ctx context.Context, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage
+	IdleNotificationHandler(ctx context.Context, sess *state.Session, bodyIn oscar.SNAC_0x01_0x11_OServiceIdleNotification) error
+	RateParamsQueryHandler(ctx context.Context, frame oscar.SNACFrame) oscar.SNACMessage
 	RateParamsSubAddHandler(context.Context, oscar.SNAC_0x01_0x08_OServiceRateParamsSubAdd)
 	RateParamsSubAddHandler(context.Context, oscar.SNAC_0x01_0x08_OServiceRateParamsSubAdd)
-	SetUserInfoFieldsHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)
-	UserInfoQueryHandler(ctx context.Context, sess *state.Session) oscar.SNACMessage
+	SetUserInfoFieldsHandler(ctx context.Context, sess *state.Session, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)
+	UserInfoQueryHandler(ctx context.Context, sess *state.Session, frame oscar.SNACFrame) oscar.SNACMessage
 }
 }
 
 
 type OServiceBOSHandler interface {
 type OServiceBOSHandler interface {
 	OServiceHandler
 	OServiceHandler
 	WriteOServiceHostOnline() oscar.SNACMessage
 	WriteOServiceHostOnline() oscar.SNACMessage
-	ServiceRequestHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x04_OServiceServiceRequest) (oscar.SNACMessage, error)
-	ClientOnlineHandler(ctx context.Context, snacPayloadIn oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session) error
+	ServiceRequestHandler(ctx context.Context, sess *state.Session, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x04_OServiceServiceRequest) (oscar.SNACMessage, error)
+	ClientOnlineHandler(ctx context.Context, bodyIn oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session) error
 }
 }
 
 
 type OServiceChatHandler interface {
 type OServiceChatHandler interface {
 	OServiceHandler
 	OServiceHandler
 	WriteOServiceHostOnline() oscar.SNACMessage
 	WriteOServiceHostOnline() oscar.SNACMessage
-	ClientOnlineHandler(ctx context.Context, snacPayloadIn oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session, chatID string) error
+	ClientOnlineHandler(ctx context.Context, bodyIn oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session, chatID string) error
 }
 }
 
 
 type OServiceRouter struct {
 type OServiceRouter struct {
@@ -37,50 +37,50 @@ type OServiceRouter struct {
 	RouteLogger
 	RouteLogger
 }
 }
 
 
-func (rt OServiceRouter) RouteOService(ctx context.Context, sess *state.Session, SNACFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
-	switch SNACFrame.SubGroup {
+func (rt OServiceRouter) RouteOService(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
+	switch inFrame.SubGroup {
 	case oscar.OServiceRateParamsQuery:
 	case oscar.OServiceRateParamsQuery:
-		outSNAC := rt.RateParamsQueryHandler(ctx)
-		rt.logRequestAndResponse(ctx, SNACFrame, nil, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		outSNAC := rt.RateParamsQueryHandler(ctx, inFrame)
+		rt.logRequestAndResponse(ctx, inFrame, nil, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.OServiceRateParamsSubAdd:
 	case oscar.OServiceRateParamsSubAdd:
-		inSNAC := oscar.SNAC_0x01_0x08_OServiceRateParamsSubAdd{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x01_0x08_OServiceRateParamsSubAdd{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		rt.RateParamsSubAddHandler(ctx, inSNAC)
-		rt.logRequest(ctx, SNACFrame, inSNAC)
-		return oscar.Unmarshal(&inSNAC, r)
+		rt.RateParamsSubAddHandler(ctx, inBody)
+		rt.logRequest(ctx, inFrame, inBody)
+		return oscar.Unmarshal(&inBody, r)
 	case oscar.OServiceUserInfoQuery:
 	case oscar.OServiceUserInfoQuery:
-		outSNAC := rt.UserInfoQueryHandler(ctx, sess)
-		rt.logRequestAndResponse(ctx, SNACFrame, nil, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		outSNAC := rt.UserInfoQueryHandler(ctx, sess, inFrame)
+		rt.logRequestAndResponse(ctx, inFrame, nil, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.OServiceIdleNotification:
 	case oscar.OServiceIdleNotification:
-		inSNAC := oscar.SNAC_0x01_0x11_OServiceIdleNotification{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x01_0x11_OServiceIdleNotification{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		rt.logRequest(ctx, SNACFrame, inSNAC)
-		return rt.IdleNotificationHandler(ctx, sess, inSNAC)
+		rt.logRequest(ctx, inFrame, inBody)
+		return rt.IdleNotificationHandler(ctx, sess, inBody)
 	case oscar.OServiceClientVersions:
 	case oscar.OServiceClientVersions:
-		inSNAC := oscar.SNAC_0x01_0x17_OServiceClientVersions{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x01_0x17_OServiceClientVersions{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC := rt.ClientVersionsHandler(ctx, inSNAC)
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		outSNAC := rt.ClientVersionsHandler(ctx, inFrame, inBody)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.OServiceSetUserInfoFields:
 	case oscar.OServiceSetUserInfoFields:
-		inSNAC := oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC, err := rt.SetUserInfoFieldsHandler(ctx, sess, inSNAC)
+		outSNAC, err := rt.SetUserInfoFieldsHandler(ctx, sess, inFrame, inBody)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	default:
 	default:
 		return ErrUnsupportedSubGroup
 		return ErrUnsupportedSubGroup
 	}
 	}
@@ -103,32 +103,32 @@ type OServiceBOSRouter struct {
 	OServiceBOSHandler
 	OServiceBOSHandler
 }
 }
 
 
-func (rt OServiceBOSRouter) RouteOService(ctx context.Context, sess *state.Session, SNACFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
-	switch SNACFrame.SubGroup {
+func (rt OServiceBOSRouter) RouteOService(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
+	switch inFrame.SubGroup {
 	case oscar.OServiceServiceRequest:
 	case oscar.OServiceServiceRequest:
-		inSNAC := oscar.SNAC_0x01_0x04_OServiceServiceRequest{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x01_0x04_OServiceServiceRequest{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
-		outSNAC, err := rt.ServiceRequestHandler(ctx, sess, inSNAC)
+		outSNAC, err := rt.ServiceRequestHandler(ctx, sess, inFrame, inBody)
 		switch {
 		switch {
 		case errors.Is(err, ErrUnsupportedSubGroup):
 		case errors.Is(err, ErrUnsupportedSubGroup):
-			return sendInvalidSNACErr(SNACFrame, w, sequence)
+			return sendInvalidSNACErr(inFrame, w, sequence)
 		case err != nil:
 		case err != nil:
 			return err
 			return err
 		}
 		}
-		rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.Frame, outSNAC.Body)
-		return sendSNAC(SNACFrame.RequestID, outSNAC.Frame, outSNAC.Body, sequence, w)
+		rt.logRequestAndResponse(ctx, inFrame, inBody, outSNAC.Frame, outSNAC.Body)
+		return sendSNAC(outSNAC.Frame, outSNAC.Body, sequence, w)
 	case oscar.OServiceClientOnline:
 	case oscar.OServiceClientOnline:
-		inSNAC := oscar.SNAC_0x01_0x02_OServiceClientOnline{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x01_0x02_OServiceClientOnline{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
 		rt.Logger.InfoContext(ctx, "user signed on")
 		rt.Logger.InfoContext(ctx, "user signed on")
-		rt.logRequest(ctx, SNACFrame, inSNAC)
-		return rt.OServiceBOSHandler.ClientOnlineHandler(ctx, inSNAC, sess)
+		rt.logRequest(ctx, inFrame, inBody)
+		return rt.OServiceBOSHandler.ClientOnlineHandler(ctx, inBody, sess)
 	default:
 	default:
-		return rt.OServiceRouter.RouteOService(ctx, sess, SNACFrame, r, w, sequence)
+		return rt.OServiceRouter.RouteOService(ctx, sess, inFrame, r, w, sequence)
 	}
 	}
 }
 }
 
 
@@ -149,19 +149,19 @@ type OServiceChatRouter struct {
 	OServiceChatHandler
 	OServiceChatHandler
 }
 }
 
 
-func (rt OServiceChatRouter) RouteOService(ctx context.Context, sess *state.Session, chatID string, SNACFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
-	switch SNACFrame.SubGroup {
+func (rt OServiceChatRouter) RouteOService(ctx context.Context, sess *state.Session, chatID string, inFrame oscar.SNACFrame, r io.Reader, w io.Writer, sequence *uint32) error {
+	switch inFrame.SubGroup {
 	case oscar.OServiceServiceRequest:
 	case oscar.OServiceServiceRequest:
-		return sendInvalidSNACErr(SNACFrame, w, sequence)
+		return sendInvalidSNACErr(inFrame, w, sequence)
 	case oscar.OServiceClientOnline:
 	case oscar.OServiceClientOnline:
-		inSNAC := oscar.SNAC_0x01_0x02_OServiceClientOnline{}
-		if err := oscar.Unmarshal(&inSNAC, r); err != nil {
+		inBody := oscar.SNAC_0x01_0x02_OServiceClientOnline{}
+		if err := oscar.Unmarshal(&inBody, r); err != nil {
 			return err
 			return err
 		}
 		}
 		rt.Logger.InfoContext(ctx, "user signed on")
 		rt.Logger.InfoContext(ctx, "user signed on")
-		rt.logRequest(ctx, SNACFrame, inSNAC)
-		return rt.OServiceChatHandler.ClientOnlineHandler(ctx, inSNAC, sess, chatID)
+		rt.logRequest(ctx, inFrame, inBody)
+		return rt.OServiceChatHandler.ClientOnlineHandler(ctx, inBody, sess, chatID)
 	default:
 	default:
-		return rt.OServiceRouter.RouteOService(ctx, sess, SNACFrame, r, w, sequence)
+		return rt.OServiceRouter.RouteOService(ctx, sess, inFrame, r, w, sequence)
 	}
 	}
 }
 }

+ 83 - 78
server/oservice_bos_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package server
 package server
 
 
@@ -24,13 +24,13 @@ func (_m *mockOServiceBOSHandler) EXPECT() *mockOServiceBOSHandler_Expecter {
 	return &mockOServiceBOSHandler_Expecter{mock: &_m.Mock}
 	return &mockOServiceBOSHandler_Expecter{mock: &_m.Mock}
 }
 }
 
 
-// ClientOnlineHandler provides a mock function with given fields: ctx, snacPayloadIn, sess
-func (_m *mockOServiceBOSHandler) ClientOnlineHandler(ctx context.Context, snacPayloadIn oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session) error {
-	ret := _m.Called(ctx, snacPayloadIn, sess)
+// ClientOnlineHandler provides a mock function with given fields: ctx, bodyIn, sess
+func (_m *mockOServiceBOSHandler) ClientOnlineHandler(ctx context.Context, bodyIn oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session) error {
+	ret := _m.Called(ctx, bodyIn, sess)
 
 
 	var r0 error
 	var r0 error
 	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNAC_0x01_0x02_OServiceClientOnline, *state.Session) error); ok {
 	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNAC_0x01_0x02_OServiceClientOnline, *state.Session) error); ok {
-		r0 = rf(ctx, snacPayloadIn, sess)
+		r0 = rf(ctx, bodyIn, sess)
 	} else {
 	} else {
 		r0 = ret.Error(0)
 		r0 = ret.Error(0)
 	}
 	}
@@ -45,13 +45,13 @@ type mockOServiceBOSHandler_ClientOnlineHandler_Call struct {
 
 
 // ClientOnlineHandler is a helper method to define mock.On call
 // ClientOnlineHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-//   - snacPayloadIn oscar.SNAC_0x01_0x02_OServiceClientOnline
+//   - bodyIn oscar.SNAC_0x01_0x02_OServiceClientOnline
 //   - sess *state.Session
 //   - sess *state.Session
-func (_e *mockOServiceBOSHandler_Expecter) ClientOnlineHandler(ctx interface{}, snacPayloadIn interface{}, sess interface{}) *mockOServiceBOSHandler_ClientOnlineHandler_Call {
-	return &mockOServiceBOSHandler_ClientOnlineHandler_Call{Call: _e.mock.On("ClientOnlineHandler", ctx, snacPayloadIn, sess)}
+func (_e *mockOServiceBOSHandler_Expecter) ClientOnlineHandler(ctx interface{}, bodyIn interface{}, sess interface{}) *mockOServiceBOSHandler_ClientOnlineHandler_Call {
+	return &mockOServiceBOSHandler_ClientOnlineHandler_Call{Call: _e.mock.On("ClientOnlineHandler", ctx, bodyIn, sess)}
 }
 }
 
 
-func (_c *mockOServiceBOSHandler_ClientOnlineHandler_Call) Run(run func(ctx context.Context, snacPayloadIn oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session)) *mockOServiceBOSHandler_ClientOnlineHandler_Call {
+func (_c *mockOServiceBOSHandler_ClientOnlineHandler_Call) Run(run func(ctx context.Context, bodyIn oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session)) *mockOServiceBOSHandler_ClientOnlineHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
 		run(args[0].(context.Context), args[1].(oscar.SNAC_0x01_0x02_OServiceClientOnline), args[2].(*state.Session))
 		run(args[0].(context.Context), args[1].(oscar.SNAC_0x01_0x02_OServiceClientOnline), args[2].(*state.Session))
 	})
 	})
@@ -68,13 +68,13 @@ func (_c *mockOServiceBOSHandler_ClientOnlineHandler_Call) RunAndReturn(run func
 	return _c
 	return _c
 }
 }
 
 
-// ClientVersionsHandler provides a mock function with given fields: ctx, snacPayloadIn
-func (_m *mockOServiceBOSHandler) ClientVersionsHandler(ctx context.Context, snacPayloadIn oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage {
-	ret := _m.Called(ctx, snacPayloadIn)
+// ClientVersionsHandler provides a mock function with given fields: ctx, frame, bodyIn
+func (_m *mockOServiceBOSHandler) ClientVersionsHandler(ctx context.Context, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage {
+	ret := _m.Called(ctx, frame, bodyIn)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage); ok {
-		r0 = rf(ctx, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame, oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage); ok {
+		r0 = rf(ctx, frame, bodyIn)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -89,14 +89,15 @@ type mockOServiceBOSHandler_ClientVersionsHandler_Call struct {
 
 
 // ClientVersionsHandler is a helper method to define mock.On call
 // ClientVersionsHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-//   - snacPayloadIn oscar.SNAC_0x01_0x17_OServiceClientVersions
-func (_e *mockOServiceBOSHandler_Expecter) ClientVersionsHandler(ctx interface{}, snacPayloadIn interface{}) *mockOServiceBOSHandler_ClientVersionsHandler_Call {
-	return &mockOServiceBOSHandler_ClientVersionsHandler_Call{Call: _e.mock.On("ClientVersionsHandler", ctx, snacPayloadIn)}
+//   - frame oscar.SNACFrame
+//   - bodyIn oscar.SNAC_0x01_0x17_OServiceClientVersions
+func (_e *mockOServiceBOSHandler_Expecter) ClientVersionsHandler(ctx interface{}, frame interface{}, bodyIn interface{}) *mockOServiceBOSHandler_ClientVersionsHandler_Call {
+	return &mockOServiceBOSHandler_ClientVersionsHandler_Call{Call: _e.mock.On("ClientVersionsHandler", ctx, frame, bodyIn)}
 }
 }
 
 
-func (_c *mockOServiceBOSHandler_ClientVersionsHandler_Call) Run(run func(ctx context.Context, snacPayloadIn oscar.SNAC_0x01_0x17_OServiceClientVersions)) *mockOServiceBOSHandler_ClientVersionsHandler_Call {
+func (_c *mockOServiceBOSHandler_ClientVersionsHandler_Call) Run(run func(ctx context.Context, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x17_OServiceClientVersions)) *mockOServiceBOSHandler_ClientVersionsHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(oscar.SNAC_0x01_0x17_OServiceClientVersions))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame), args[2].(oscar.SNAC_0x01_0x17_OServiceClientVersions))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -106,18 +107,18 @@ func (_c *mockOServiceBOSHandler_ClientVersionsHandler_Call) Return(_a0 oscar.SN
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockOServiceBOSHandler_ClientVersionsHandler_Call) RunAndReturn(run func(context.Context, oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage) *mockOServiceBOSHandler_ClientVersionsHandler_Call {
+func (_c *mockOServiceBOSHandler_ClientVersionsHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame, oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage) *mockOServiceBOSHandler_ClientVersionsHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// IdleNotificationHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockOServiceBOSHandler) IdleNotificationHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x11_OServiceIdleNotification) error {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// IdleNotificationHandler provides a mock function with given fields: ctx, sess, bodyIn
+func (_m *mockOServiceBOSHandler) IdleNotificationHandler(ctx context.Context, sess *state.Session, bodyIn oscar.SNAC_0x01_0x11_OServiceIdleNotification) error {
+	ret := _m.Called(ctx, sess, bodyIn)
 
 
 	var r0 error
 	var r0 error
 	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x11_OServiceIdleNotification) error); ok {
 	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x11_OServiceIdleNotification) error); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+		r0 = rf(ctx, sess, bodyIn)
 	} else {
 	} else {
 		r0 = ret.Error(0)
 		r0 = ret.Error(0)
 	}
 	}
@@ -133,12 +134,12 @@ type mockOServiceBOSHandler_IdleNotificationHandler_Call struct {
 // IdleNotificationHandler is a helper method to define mock.On call
 // IdleNotificationHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x01_0x11_OServiceIdleNotification
-func (_e *mockOServiceBOSHandler_Expecter) IdleNotificationHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockOServiceBOSHandler_IdleNotificationHandler_Call {
-	return &mockOServiceBOSHandler_IdleNotificationHandler_Call{Call: _e.mock.On("IdleNotificationHandler", ctx, sess, snacPayloadIn)}
+//   - bodyIn oscar.SNAC_0x01_0x11_OServiceIdleNotification
+func (_e *mockOServiceBOSHandler_Expecter) IdleNotificationHandler(ctx interface{}, sess interface{}, bodyIn interface{}) *mockOServiceBOSHandler_IdleNotificationHandler_Call {
+	return &mockOServiceBOSHandler_IdleNotificationHandler_Call{Call: _e.mock.On("IdleNotificationHandler", ctx, sess, bodyIn)}
 }
 }
 
 
-func (_c *mockOServiceBOSHandler_IdleNotificationHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x11_OServiceIdleNotification)) *mockOServiceBOSHandler_IdleNotificationHandler_Call {
+func (_c *mockOServiceBOSHandler_IdleNotificationHandler_Call) Run(run func(ctx context.Context, sess *state.Session, bodyIn oscar.SNAC_0x01_0x11_OServiceIdleNotification)) *mockOServiceBOSHandler_IdleNotificationHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
 		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x01_0x11_OServiceIdleNotification))
 		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x01_0x11_OServiceIdleNotification))
 	})
 	})
@@ -155,13 +156,13 @@ func (_c *mockOServiceBOSHandler_IdleNotificationHandler_Call) RunAndReturn(run
 	return _c
 	return _c
 }
 }
 
 
-// RateParamsQueryHandler provides a mock function with given fields: ctx
-func (_m *mockOServiceBOSHandler) RateParamsQueryHandler(ctx context.Context) oscar.SNACMessage {
-	ret := _m.Called(ctx)
+// RateParamsQueryHandler provides a mock function with given fields: ctx, frame
+func (_m *mockOServiceBOSHandler) RateParamsQueryHandler(ctx context.Context, frame oscar.SNACFrame) oscar.SNACMessage {
+	ret := _m.Called(ctx, frame)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context) oscar.SNACMessage); ok {
-		r0 = rf(ctx)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame) oscar.SNACMessage); ok {
+		r0 = rf(ctx, frame)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -176,13 +177,14 @@ type mockOServiceBOSHandler_RateParamsQueryHandler_Call struct {
 
 
 // RateParamsQueryHandler is a helper method to define mock.On call
 // RateParamsQueryHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-func (_e *mockOServiceBOSHandler_Expecter) RateParamsQueryHandler(ctx interface{}) *mockOServiceBOSHandler_RateParamsQueryHandler_Call {
-	return &mockOServiceBOSHandler_RateParamsQueryHandler_Call{Call: _e.mock.On("RateParamsQueryHandler", ctx)}
+//   - frame oscar.SNACFrame
+func (_e *mockOServiceBOSHandler_Expecter) RateParamsQueryHandler(ctx interface{}, frame interface{}) *mockOServiceBOSHandler_RateParamsQueryHandler_Call {
+	return &mockOServiceBOSHandler_RateParamsQueryHandler_Call{Call: _e.mock.On("RateParamsQueryHandler", ctx, frame)}
 }
 }
 
 
-func (_c *mockOServiceBOSHandler_RateParamsQueryHandler_Call) Run(run func(ctx context.Context)) *mockOServiceBOSHandler_RateParamsQueryHandler_Call {
+func (_c *mockOServiceBOSHandler_RateParamsQueryHandler_Call) Run(run func(ctx context.Context, frame oscar.SNACFrame)) *mockOServiceBOSHandler_RateParamsQueryHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -192,7 +194,7 @@ func (_c *mockOServiceBOSHandler_RateParamsQueryHandler_Call) Return(_a0 oscar.S
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockOServiceBOSHandler_RateParamsQueryHandler_Call) RunAndReturn(run func(context.Context) oscar.SNACMessage) *mockOServiceBOSHandler_RateParamsQueryHandler_Call {
+func (_c *mockOServiceBOSHandler_RateParamsQueryHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame) oscar.SNACMessage) *mockOServiceBOSHandler_RateParamsQueryHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
@@ -231,23 +233,23 @@ func (_c *mockOServiceBOSHandler_RateParamsSubAddHandler_Call) RunAndReturn(run
 	return _c
 	return _c
 }
 }
 
 
-// ServiceRequestHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockOServiceBOSHandler) ServiceRequestHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x04_OServiceServiceRequest) (oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// ServiceRequestHandler provides a mock function with given fields: ctx, sess, frame, bodyIn
+func (_m *mockOServiceBOSHandler) ServiceRequestHandler(ctx context.Context, sess *state.Session, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x04_OServiceServiceRequest) (oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, frame, bodyIn)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x04_OServiceServiceRequest) (oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x04_OServiceServiceRequest) (oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, frame, bodyIn)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x04_OServiceServiceRequest) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x04_OServiceServiceRequest) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, frame, bodyIn)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x04_OServiceServiceRequest) error); ok {
-		r1 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x04_OServiceServiceRequest) error); ok {
+		r1 = rf(ctx, sess, frame, bodyIn)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -263,14 +265,15 @@ type mockOServiceBOSHandler_ServiceRequestHandler_Call struct {
 // ServiceRequestHandler is a helper method to define mock.On call
 // ServiceRequestHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x01_0x04_OServiceServiceRequest
-func (_e *mockOServiceBOSHandler_Expecter) ServiceRequestHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockOServiceBOSHandler_ServiceRequestHandler_Call {
-	return &mockOServiceBOSHandler_ServiceRequestHandler_Call{Call: _e.mock.On("ServiceRequestHandler", ctx, sess, snacPayloadIn)}
+//   - frame oscar.SNACFrame
+//   - bodyIn oscar.SNAC_0x01_0x04_OServiceServiceRequest
+func (_e *mockOServiceBOSHandler_Expecter) ServiceRequestHandler(ctx interface{}, sess interface{}, frame interface{}, bodyIn interface{}) *mockOServiceBOSHandler_ServiceRequestHandler_Call {
+	return &mockOServiceBOSHandler_ServiceRequestHandler_Call{Call: _e.mock.On("ServiceRequestHandler", ctx, sess, frame, bodyIn)}
 }
 }
 
 
-func (_c *mockOServiceBOSHandler_ServiceRequestHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x04_OServiceServiceRequest)) *mockOServiceBOSHandler_ServiceRequestHandler_Call {
+func (_c *mockOServiceBOSHandler_ServiceRequestHandler_Call) Run(run func(ctx context.Context, sess *state.Session, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x04_OServiceServiceRequest)) *mockOServiceBOSHandler_ServiceRequestHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x01_0x04_OServiceServiceRequest))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame), args[3].(oscar.SNAC_0x01_0x04_OServiceServiceRequest))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -280,28 +283,28 @@ func (_c *mockOServiceBOSHandler_ServiceRequestHandler_Call) Return(_a0 oscar.SN
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockOServiceBOSHandler_ServiceRequestHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNAC_0x01_0x04_OServiceServiceRequest) (oscar.SNACMessage, error)) *mockOServiceBOSHandler_ServiceRequestHandler_Call {
+func (_c *mockOServiceBOSHandler_ServiceRequestHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x04_OServiceServiceRequest) (oscar.SNACMessage, error)) *mockOServiceBOSHandler_ServiceRequestHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// SetUserInfoFieldsHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockOServiceBOSHandler) SetUserInfoFieldsHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// SetUserInfoFieldsHandler provides a mock function with given fields: ctx, sess, frame, bodyIn
+func (_m *mockOServiceBOSHandler) SetUserInfoFieldsHandler(ctx context.Context, sess *state.Session, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, frame, bodyIn)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, frame, bodyIn)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, frame, bodyIn)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) error); ok {
-		r1 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) error); ok {
+		r1 = rf(ctx, sess, frame, bodyIn)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -317,14 +320,15 @@ type mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call struct {
 // SetUserInfoFieldsHandler is a helper method to define mock.On call
 // SetUserInfoFieldsHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields
-func (_e *mockOServiceBOSHandler_Expecter) SetUserInfoFieldsHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call {
-	return &mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call{Call: _e.mock.On("SetUserInfoFieldsHandler", ctx, sess, snacPayloadIn)}
+//   - frame oscar.SNACFrame
+//   - bodyIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields
+func (_e *mockOServiceBOSHandler_Expecter) SetUserInfoFieldsHandler(ctx interface{}, sess interface{}, frame interface{}, bodyIn interface{}) *mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call {
+	return &mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call{Call: _e.mock.On("SetUserInfoFieldsHandler", ctx, sess, frame, bodyIn)}
 }
 }
 
 
-func (_c *mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields)) *mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call {
+func (_c *mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call) Run(run func(ctx context.Context, sess *state.Session, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields)) *mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame), args[3].(oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -334,18 +338,18 @@ func (_c *mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call) Return(_a0 oscar
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)) *mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call {
+func (_c *mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)) *mockOServiceBOSHandler_SetUserInfoFieldsHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// UserInfoQueryHandler provides a mock function with given fields: ctx, sess
-func (_m *mockOServiceBOSHandler) UserInfoQueryHandler(ctx context.Context, sess *state.Session) oscar.SNACMessage {
-	ret := _m.Called(ctx, sess)
+// UserInfoQueryHandler provides a mock function with given fields: ctx, sess, frame
+func (_m *mockOServiceBOSHandler) UserInfoQueryHandler(ctx context.Context, sess *state.Session, frame oscar.SNACFrame) oscar.SNACMessage {
+	ret := _m.Called(ctx, sess, frame)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, frame)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -361,13 +365,14 @@ type mockOServiceBOSHandler_UserInfoQueryHandler_Call struct {
 // UserInfoQueryHandler is a helper method to define mock.On call
 // UserInfoQueryHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-func (_e *mockOServiceBOSHandler_Expecter) UserInfoQueryHandler(ctx interface{}, sess interface{}) *mockOServiceBOSHandler_UserInfoQueryHandler_Call {
-	return &mockOServiceBOSHandler_UserInfoQueryHandler_Call{Call: _e.mock.On("UserInfoQueryHandler", ctx, sess)}
+//   - frame oscar.SNACFrame
+func (_e *mockOServiceBOSHandler_Expecter) UserInfoQueryHandler(ctx interface{}, sess interface{}, frame interface{}) *mockOServiceBOSHandler_UserInfoQueryHandler_Call {
+	return &mockOServiceBOSHandler_UserInfoQueryHandler_Call{Call: _e.mock.On("UserInfoQueryHandler", ctx, sess, frame)}
 }
 }
 
 
-func (_c *mockOServiceBOSHandler_UserInfoQueryHandler_Call) Run(run func(ctx context.Context, sess *state.Session)) *mockOServiceBOSHandler_UserInfoQueryHandler_Call {
+func (_c *mockOServiceBOSHandler_UserInfoQueryHandler_Call) Run(run func(ctx context.Context, sess *state.Session, frame oscar.SNACFrame)) *mockOServiceBOSHandler_UserInfoQueryHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -377,7 +382,7 @@ func (_c *mockOServiceBOSHandler_UserInfoQueryHandler_Call) Return(_a0 oscar.SNA
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockOServiceBOSHandler_UserInfoQueryHandler_Call) RunAndReturn(run func(context.Context, *state.Session) oscar.SNACMessage) *mockOServiceBOSHandler_UserInfoQueryHandler_Call {
+func (_c *mockOServiceBOSHandler_UserInfoQueryHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame) oscar.SNACMessage) *mockOServiceBOSHandler_UserInfoQueryHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 67 - 63
server/oservice_chat_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package server
 package server
 
 
@@ -24,13 +24,13 @@ func (_m *mockOServiceChatHandler) EXPECT() *mockOServiceChatHandler_Expecter {
 	return &mockOServiceChatHandler_Expecter{mock: &_m.Mock}
 	return &mockOServiceChatHandler_Expecter{mock: &_m.Mock}
 }
 }
 
 
-// ClientOnlineHandler provides a mock function with given fields: ctx, snacPayloadIn, sess, chatID
-func (_m *mockOServiceChatHandler) ClientOnlineHandler(ctx context.Context, snacPayloadIn oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session, chatID string) error {
-	ret := _m.Called(ctx, snacPayloadIn, sess, chatID)
+// ClientOnlineHandler provides a mock function with given fields: ctx, bodyIn, sess, chatID
+func (_m *mockOServiceChatHandler) ClientOnlineHandler(ctx context.Context, bodyIn oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session, chatID string) error {
+	ret := _m.Called(ctx, bodyIn, sess, chatID)
 
 
 	var r0 error
 	var r0 error
 	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNAC_0x01_0x02_OServiceClientOnline, *state.Session, string) error); ok {
 	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNAC_0x01_0x02_OServiceClientOnline, *state.Session, string) error); ok {
-		r0 = rf(ctx, snacPayloadIn, sess, chatID)
+		r0 = rf(ctx, bodyIn, sess, chatID)
 	} else {
 	} else {
 		r0 = ret.Error(0)
 		r0 = ret.Error(0)
 	}
 	}
@@ -45,14 +45,14 @@ type mockOServiceChatHandler_ClientOnlineHandler_Call struct {
 
 
 // ClientOnlineHandler is a helper method to define mock.On call
 // ClientOnlineHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-//   - snacPayloadIn oscar.SNAC_0x01_0x02_OServiceClientOnline
+//   - bodyIn oscar.SNAC_0x01_0x02_OServiceClientOnline
 //   - sess *state.Session
 //   - sess *state.Session
 //   - chatID string
 //   - chatID string
-func (_e *mockOServiceChatHandler_Expecter) ClientOnlineHandler(ctx interface{}, snacPayloadIn interface{}, sess interface{}, chatID interface{}) *mockOServiceChatHandler_ClientOnlineHandler_Call {
-	return &mockOServiceChatHandler_ClientOnlineHandler_Call{Call: _e.mock.On("ClientOnlineHandler", ctx, snacPayloadIn, sess, chatID)}
+func (_e *mockOServiceChatHandler_Expecter) ClientOnlineHandler(ctx interface{}, bodyIn interface{}, sess interface{}, chatID interface{}) *mockOServiceChatHandler_ClientOnlineHandler_Call {
+	return &mockOServiceChatHandler_ClientOnlineHandler_Call{Call: _e.mock.On("ClientOnlineHandler", ctx, bodyIn, sess, chatID)}
 }
 }
 
 
-func (_c *mockOServiceChatHandler_ClientOnlineHandler_Call) Run(run func(ctx context.Context, snacPayloadIn oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session, chatID string)) *mockOServiceChatHandler_ClientOnlineHandler_Call {
+func (_c *mockOServiceChatHandler_ClientOnlineHandler_Call) Run(run func(ctx context.Context, bodyIn oscar.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session, chatID string)) *mockOServiceChatHandler_ClientOnlineHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
 		run(args[0].(context.Context), args[1].(oscar.SNAC_0x01_0x02_OServiceClientOnline), args[2].(*state.Session), args[3].(string))
 		run(args[0].(context.Context), args[1].(oscar.SNAC_0x01_0x02_OServiceClientOnline), args[2].(*state.Session), args[3].(string))
 	})
 	})
@@ -69,13 +69,13 @@ func (_c *mockOServiceChatHandler_ClientOnlineHandler_Call) RunAndReturn(run fun
 	return _c
 	return _c
 }
 }
 
 
-// ClientVersionsHandler provides a mock function with given fields: ctx, snacPayloadIn
-func (_m *mockOServiceChatHandler) ClientVersionsHandler(ctx context.Context, snacPayloadIn oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage {
-	ret := _m.Called(ctx, snacPayloadIn)
+// ClientVersionsHandler provides a mock function with given fields: ctx, frame, bodyIn
+func (_m *mockOServiceChatHandler) ClientVersionsHandler(ctx context.Context, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage {
+	ret := _m.Called(ctx, frame, bodyIn)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage); ok {
-		r0 = rf(ctx, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame, oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage); ok {
+		r0 = rf(ctx, frame, bodyIn)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -90,14 +90,15 @@ type mockOServiceChatHandler_ClientVersionsHandler_Call struct {
 
 
 // ClientVersionsHandler is a helper method to define mock.On call
 // ClientVersionsHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-//   - snacPayloadIn oscar.SNAC_0x01_0x17_OServiceClientVersions
-func (_e *mockOServiceChatHandler_Expecter) ClientVersionsHandler(ctx interface{}, snacPayloadIn interface{}) *mockOServiceChatHandler_ClientVersionsHandler_Call {
-	return &mockOServiceChatHandler_ClientVersionsHandler_Call{Call: _e.mock.On("ClientVersionsHandler", ctx, snacPayloadIn)}
+//   - frame oscar.SNACFrame
+//   - bodyIn oscar.SNAC_0x01_0x17_OServiceClientVersions
+func (_e *mockOServiceChatHandler_Expecter) ClientVersionsHandler(ctx interface{}, frame interface{}, bodyIn interface{}) *mockOServiceChatHandler_ClientVersionsHandler_Call {
+	return &mockOServiceChatHandler_ClientVersionsHandler_Call{Call: _e.mock.On("ClientVersionsHandler", ctx, frame, bodyIn)}
 }
 }
 
 
-func (_c *mockOServiceChatHandler_ClientVersionsHandler_Call) Run(run func(ctx context.Context, snacPayloadIn oscar.SNAC_0x01_0x17_OServiceClientVersions)) *mockOServiceChatHandler_ClientVersionsHandler_Call {
+func (_c *mockOServiceChatHandler_ClientVersionsHandler_Call) Run(run func(ctx context.Context, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x17_OServiceClientVersions)) *mockOServiceChatHandler_ClientVersionsHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(oscar.SNAC_0x01_0x17_OServiceClientVersions))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame), args[2].(oscar.SNAC_0x01_0x17_OServiceClientVersions))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -107,18 +108,18 @@ func (_c *mockOServiceChatHandler_ClientVersionsHandler_Call) Return(_a0 oscar.S
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockOServiceChatHandler_ClientVersionsHandler_Call) RunAndReturn(run func(context.Context, oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage) *mockOServiceChatHandler_ClientVersionsHandler_Call {
+func (_c *mockOServiceChatHandler_ClientVersionsHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame, oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage) *mockOServiceChatHandler_ClientVersionsHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// IdleNotificationHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockOServiceChatHandler) IdleNotificationHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x11_OServiceIdleNotification) error {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// IdleNotificationHandler provides a mock function with given fields: ctx, sess, bodyIn
+func (_m *mockOServiceChatHandler) IdleNotificationHandler(ctx context.Context, sess *state.Session, bodyIn oscar.SNAC_0x01_0x11_OServiceIdleNotification) error {
+	ret := _m.Called(ctx, sess, bodyIn)
 
 
 	var r0 error
 	var r0 error
 	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x11_OServiceIdleNotification) error); ok {
 	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x11_OServiceIdleNotification) error); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+		r0 = rf(ctx, sess, bodyIn)
 	} else {
 	} else {
 		r0 = ret.Error(0)
 		r0 = ret.Error(0)
 	}
 	}
@@ -134,12 +135,12 @@ type mockOServiceChatHandler_IdleNotificationHandler_Call struct {
 // IdleNotificationHandler is a helper method to define mock.On call
 // IdleNotificationHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x01_0x11_OServiceIdleNotification
-func (_e *mockOServiceChatHandler_Expecter) IdleNotificationHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockOServiceChatHandler_IdleNotificationHandler_Call {
-	return &mockOServiceChatHandler_IdleNotificationHandler_Call{Call: _e.mock.On("IdleNotificationHandler", ctx, sess, snacPayloadIn)}
+//   - bodyIn oscar.SNAC_0x01_0x11_OServiceIdleNotification
+func (_e *mockOServiceChatHandler_Expecter) IdleNotificationHandler(ctx interface{}, sess interface{}, bodyIn interface{}) *mockOServiceChatHandler_IdleNotificationHandler_Call {
+	return &mockOServiceChatHandler_IdleNotificationHandler_Call{Call: _e.mock.On("IdleNotificationHandler", ctx, sess, bodyIn)}
 }
 }
 
 
-func (_c *mockOServiceChatHandler_IdleNotificationHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x11_OServiceIdleNotification)) *mockOServiceChatHandler_IdleNotificationHandler_Call {
+func (_c *mockOServiceChatHandler_IdleNotificationHandler_Call) Run(run func(ctx context.Context, sess *state.Session, bodyIn oscar.SNAC_0x01_0x11_OServiceIdleNotification)) *mockOServiceChatHandler_IdleNotificationHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
 		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x01_0x11_OServiceIdleNotification))
 		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x01_0x11_OServiceIdleNotification))
 	})
 	})
@@ -156,13 +157,13 @@ func (_c *mockOServiceChatHandler_IdleNotificationHandler_Call) RunAndReturn(run
 	return _c
 	return _c
 }
 }
 
 
-// RateParamsQueryHandler provides a mock function with given fields: ctx
-func (_m *mockOServiceChatHandler) RateParamsQueryHandler(ctx context.Context) oscar.SNACMessage {
-	ret := _m.Called(ctx)
+// RateParamsQueryHandler provides a mock function with given fields: ctx, frame
+func (_m *mockOServiceChatHandler) RateParamsQueryHandler(ctx context.Context, frame oscar.SNACFrame) oscar.SNACMessage {
+	ret := _m.Called(ctx, frame)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context) oscar.SNACMessage); ok {
-		r0 = rf(ctx)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame) oscar.SNACMessage); ok {
+		r0 = rf(ctx, frame)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -177,13 +178,14 @@ type mockOServiceChatHandler_RateParamsQueryHandler_Call struct {
 
 
 // RateParamsQueryHandler is a helper method to define mock.On call
 // RateParamsQueryHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-func (_e *mockOServiceChatHandler_Expecter) RateParamsQueryHandler(ctx interface{}) *mockOServiceChatHandler_RateParamsQueryHandler_Call {
-	return &mockOServiceChatHandler_RateParamsQueryHandler_Call{Call: _e.mock.On("RateParamsQueryHandler", ctx)}
+//   - frame oscar.SNACFrame
+func (_e *mockOServiceChatHandler_Expecter) RateParamsQueryHandler(ctx interface{}, frame interface{}) *mockOServiceChatHandler_RateParamsQueryHandler_Call {
+	return &mockOServiceChatHandler_RateParamsQueryHandler_Call{Call: _e.mock.On("RateParamsQueryHandler", ctx, frame)}
 }
 }
 
 
-func (_c *mockOServiceChatHandler_RateParamsQueryHandler_Call) Run(run func(ctx context.Context)) *mockOServiceChatHandler_RateParamsQueryHandler_Call {
+func (_c *mockOServiceChatHandler_RateParamsQueryHandler_Call) Run(run func(ctx context.Context, frame oscar.SNACFrame)) *mockOServiceChatHandler_RateParamsQueryHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -193,7 +195,7 @@ func (_c *mockOServiceChatHandler_RateParamsQueryHandler_Call) Return(_a0 oscar.
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockOServiceChatHandler_RateParamsQueryHandler_Call) RunAndReturn(run func(context.Context) oscar.SNACMessage) *mockOServiceChatHandler_RateParamsQueryHandler_Call {
+func (_c *mockOServiceChatHandler_RateParamsQueryHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame) oscar.SNACMessage) *mockOServiceChatHandler_RateParamsQueryHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
@@ -232,23 +234,23 @@ func (_c *mockOServiceChatHandler_RateParamsSubAddHandler_Call) RunAndReturn(run
 	return _c
 	return _c
 }
 }
 
 
-// SetUserInfoFieldsHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockOServiceChatHandler) SetUserInfoFieldsHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// SetUserInfoFieldsHandler provides a mock function with given fields: ctx, sess, frame, bodyIn
+func (_m *mockOServiceChatHandler) SetUserInfoFieldsHandler(ctx context.Context, sess *state.Session, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, frame, bodyIn)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, frame, bodyIn)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, frame, bodyIn)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) error); ok {
-		r1 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) error); ok {
+		r1 = rf(ctx, sess, frame, bodyIn)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -264,14 +266,15 @@ type mockOServiceChatHandler_SetUserInfoFieldsHandler_Call struct {
 // SetUserInfoFieldsHandler is a helper method to define mock.On call
 // SetUserInfoFieldsHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields
-func (_e *mockOServiceChatHandler_Expecter) SetUserInfoFieldsHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockOServiceChatHandler_SetUserInfoFieldsHandler_Call {
-	return &mockOServiceChatHandler_SetUserInfoFieldsHandler_Call{Call: _e.mock.On("SetUserInfoFieldsHandler", ctx, sess, snacPayloadIn)}
+//   - frame oscar.SNACFrame
+//   - bodyIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields
+func (_e *mockOServiceChatHandler_Expecter) SetUserInfoFieldsHandler(ctx interface{}, sess interface{}, frame interface{}, bodyIn interface{}) *mockOServiceChatHandler_SetUserInfoFieldsHandler_Call {
+	return &mockOServiceChatHandler_SetUserInfoFieldsHandler_Call{Call: _e.mock.On("SetUserInfoFieldsHandler", ctx, sess, frame, bodyIn)}
 }
 }
 
 
-func (_c *mockOServiceChatHandler_SetUserInfoFieldsHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields)) *mockOServiceChatHandler_SetUserInfoFieldsHandler_Call {
+func (_c *mockOServiceChatHandler_SetUserInfoFieldsHandler_Call) Run(run func(ctx context.Context, sess *state.Session, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields)) *mockOServiceChatHandler_SetUserInfoFieldsHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame), args[3].(oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -281,18 +284,18 @@ func (_c *mockOServiceChatHandler_SetUserInfoFieldsHandler_Call) Return(_a0 osca
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockOServiceChatHandler_SetUserInfoFieldsHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)) *mockOServiceChatHandler_SetUserInfoFieldsHandler_Call {
+func (_c *mockOServiceChatHandler_SetUserInfoFieldsHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)) *mockOServiceChatHandler_SetUserInfoFieldsHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// UserInfoQueryHandler provides a mock function with given fields: ctx, sess
-func (_m *mockOServiceChatHandler) UserInfoQueryHandler(ctx context.Context, sess *state.Session) oscar.SNACMessage {
-	ret := _m.Called(ctx, sess)
+// UserInfoQueryHandler provides a mock function with given fields: ctx, sess, frame
+func (_m *mockOServiceChatHandler) UserInfoQueryHandler(ctx context.Context, sess *state.Session, frame oscar.SNACFrame) oscar.SNACMessage {
+	ret := _m.Called(ctx, sess, frame)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, frame)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -308,13 +311,14 @@ type mockOServiceChatHandler_UserInfoQueryHandler_Call struct {
 // UserInfoQueryHandler is a helper method to define mock.On call
 // UserInfoQueryHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-func (_e *mockOServiceChatHandler_Expecter) UserInfoQueryHandler(ctx interface{}, sess interface{}) *mockOServiceChatHandler_UserInfoQueryHandler_Call {
-	return &mockOServiceChatHandler_UserInfoQueryHandler_Call{Call: _e.mock.On("UserInfoQueryHandler", ctx, sess)}
+//   - frame oscar.SNACFrame
+func (_e *mockOServiceChatHandler_Expecter) UserInfoQueryHandler(ctx interface{}, sess interface{}, frame interface{}) *mockOServiceChatHandler_UserInfoQueryHandler_Call {
+	return &mockOServiceChatHandler_UserInfoQueryHandler_Call{Call: _e.mock.On("UserInfoQueryHandler", ctx, sess, frame)}
 }
 }
 
 
-func (_c *mockOServiceChatHandler_UserInfoQueryHandler_Call) Run(run func(ctx context.Context, sess *state.Session)) *mockOServiceChatHandler_UserInfoQueryHandler_Call {
+func (_c *mockOServiceChatHandler_UserInfoQueryHandler_Call) Run(run func(ctx context.Context, sess *state.Session, frame oscar.SNACFrame)) *mockOServiceChatHandler_UserInfoQueryHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -324,7 +328,7 @@ func (_c *mockOServiceChatHandler_UserInfoQueryHandler_Call) Return(_a0 oscar.SN
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockOServiceChatHandler_UserInfoQueryHandler_Call) RunAndReturn(run func(context.Context, *state.Session) oscar.SNACMessage) *mockOServiceChatHandler_UserInfoQueryHandler_Call {
+func (_c *mockOServiceChatHandler_UserInfoQueryHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame) oscar.SNACMessage) *mockOServiceChatHandler_UserInfoQueryHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 59 - 55
server/oservice_mock.go

@@ -1,4 +1,4 @@
-// Code generated by mockery v2.34.2. DO NOT EDIT.
+// Code generated by mockery v2.35.2. DO NOT EDIT.
 
 
 package server
 package server
 
 
@@ -24,13 +24,13 @@ func (_m *mockOServiceHandler) EXPECT() *mockOServiceHandler_Expecter {
 	return &mockOServiceHandler_Expecter{mock: &_m.Mock}
 	return &mockOServiceHandler_Expecter{mock: &_m.Mock}
 }
 }
 
 
-// ClientVersionsHandler provides a mock function with given fields: ctx, snacPayloadIn
-func (_m *mockOServiceHandler) ClientVersionsHandler(ctx context.Context, snacPayloadIn oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage {
-	ret := _m.Called(ctx, snacPayloadIn)
+// ClientVersionsHandler provides a mock function with given fields: ctx, frame, bodyIn
+func (_m *mockOServiceHandler) ClientVersionsHandler(ctx context.Context, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage {
+	ret := _m.Called(ctx, frame, bodyIn)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage); ok {
-		r0 = rf(ctx, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame, oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage); ok {
+		r0 = rf(ctx, frame, bodyIn)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -45,14 +45,15 @@ type mockOServiceHandler_ClientVersionsHandler_Call struct {
 
 
 // ClientVersionsHandler is a helper method to define mock.On call
 // ClientVersionsHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-//   - snacPayloadIn oscar.SNAC_0x01_0x17_OServiceClientVersions
-func (_e *mockOServiceHandler_Expecter) ClientVersionsHandler(ctx interface{}, snacPayloadIn interface{}) *mockOServiceHandler_ClientVersionsHandler_Call {
-	return &mockOServiceHandler_ClientVersionsHandler_Call{Call: _e.mock.On("ClientVersionsHandler", ctx, snacPayloadIn)}
+//   - frame oscar.SNACFrame
+//   - bodyIn oscar.SNAC_0x01_0x17_OServiceClientVersions
+func (_e *mockOServiceHandler_Expecter) ClientVersionsHandler(ctx interface{}, frame interface{}, bodyIn interface{}) *mockOServiceHandler_ClientVersionsHandler_Call {
+	return &mockOServiceHandler_ClientVersionsHandler_Call{Call: _e.mock.On("ClientVersionsHandler", ctx, frame, bodyIn)}
 }
 }
 
 
-func (_c *mockOServiceHandler_ClientVersionsHandler_Call) Run(run func(ctx context.Context, snacPayloadIn oscar.SNAC_0x01_0x17_OServiceClientVersions)) *mockOServiceHandler_ClientVersionsHandler_Call {
+func (_c *mockOServiceHandler_ClientVersionsHandler_Call) Run(run func(ctx context.Context, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x17_OServiceClientVersions)) *mockOServiceHandler_ClientVersionsHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(oscar.SNAC_0x01_0x17_OServiceClientVersions))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame), args[2].(oscar.SNAC_0x01_0x17_OServiceClientVersions))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -62,18 +63,18 @@ func (_c *mockOServiceHandler_ClientVersionsHandler_Call) Return(_a0 oscar.SNACM
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockOServiceHandler_ClientVersionsHandler_Call) RunAndReturn(run func(context.Context, oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage) *mockOServiceHandler_ClientVersionsHandler_Call {
+func (_c *mockOServiceHandler_ClientVersionsHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame, oscar.SNAC_0x01_0x17_OServiceClientVersions) oscar.SNACMessage) *mockOServiceHandler_ClientVersionsHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// IdleNotificationHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockOServiceHandler) IdleNotificationHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x11_OServiceIdleNotification) error {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// IdleNotificationHandler provides a mock function with given fields: ctx, sess, bodyIn
+func (_m *mockOServiceHandler) IdleNotificationHandler(ctx context.Context, sess *state.Session, bodyIn oscar.SNAC_0x01_0x11_OServiceIdleNotification) error {
+	ret := _m.Called(ctx, sess, bodyIn)
 
 
 	var r0 error
 	var r0 error
 	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x11_OServiceIdleNotification) error); ok {
 	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x11_OServiceIdleNotification) error); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+		r0 = rf(ctx, sess, bodyIn)
 	} else {
 	} else {
 		r0 = ret.Error(0)
 		r0 = ret.Error(0)
 	}
 	}
@@ -89,12 +90,12 @@ type mockOServiceHandler_IdleNotificationHandler_Call struct {
 // IdleNotificationHandler is a helper method to define mock.On call
 // IdleNotificationHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x01_0x11_OServiceIdleNotification
-func (_e *mockOServiceHandler_Expecter) IdleNotificationHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockOServiceHandler_IdleNotificationHandler_Call {
-	return &mockOServiceHandler_IdleNotificationHandler_Call{Call: _e.mock.On("IdleNotificationHandler", ctx, sess, snacPayloadIn)}
+//   - bodyIn oscar.SNAC_0x01_0x11_OServiceIdleNotification
+func (_e *mockOServiceHandler_Expecter) IdleNotificationHandler(ctx interface{}, sess interface{}, bodyIn interface{}) *mockOServiceHandler_IdleNotificationHandler_Call {
+	return &mockOServiceHandler_IdleNotificationHandler_Call{Call: _e.mock.On("IdleNotificationHandler", ctx, sess, bodyIn)}
 }
 }
 
 
-func (_c *mockOServiceHandler_IdleNotificationHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x11_OServiceIdleNotification)) *mockOServiceHandler_IdleNotificationHandler_Call {
+func (_c *mockOServiceHandler_IdleNotificationHandler_Call) Run(run func(ctx context.Context, sess *state.Session, bodyIn oscar.SNAC_0x01_0x11_OServiceIdleNotification)) *mockOServiceHandler_IdleNotificationHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
 		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x01_0x11_OServiceIdleNotification))
 		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x01_0x11_OServiceIdleNotification))
 	})
 	})
@@ -111,13 +112,13 @@ func (_c *mockOServiceHandler_IdleNotificationHandler_Call) RunAndReturn(run fun
 	return _c
 	return _c
 }
 }
 
 
-// RateParamsQueryHandler provides a mock function with given fields: ctx
-func (_m *mockOServiceHandler) RateParamsQueryHandler(ctx context.Context) oscar.SNACMessage {
-	ret := _m.Called(ctx)
+// RateParamsQueryHandler provides a mock function with given fields: ctx, frame
+func (_m *mockOServiceHandler) RateParamsQueryHandler(ctx context.Context, frame oscar.SNACFrame) oscar.SNACMessage {
+	ret := _m.Called(ctx, frame)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context) oscar.SNACMessage); ok {
-		r0 = rf(ctx)
+	if rf, ok := ret.Get(0).(func(context.Context, oscar.SNACFrame) oscar.SNACMessage); ok {
+		r0 = rf(ctx, frame)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -132,13 +133,14 @@ type mockOServiceHandler_RateParamsQueryHandler_Call struct {
 
 
 // RateParamsQueryHandler is a helper method to define mock.On call
 // RateParamsQueryHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-func (_e *mockOServiceHandler_Expecter) RateParamsQueryHandler(ctx interface{}) *mockOServiceHandler_RateParamsQueryHandler_Call {
-	return &mockOServiceHandler_RateParamsQueryHandler_Call{Call: _e.mock.On("RateParamsQueryHandler", ctx)}
+//   - frame oscar.SNACFrame
+func (_e *mockOServiceHandler_Expecter) RateParamsQueryHandler(ctx interface{}, frame interface{}) *mockOServiceHandler_RateParamsQueryHandler_Call {
+	return &mockOServiceHandler_RateParamsQueryHandler_Call{Call: _e.mock.On("RateParamsQueryHandler", ctx, frame)}
 }
 }
 
 
-func (_c *mockOServiceHandler_RateParamsQueryHandler_Call) Run(run func(ctx context.Context)) *mockOServiceHandler_RateParamsQueryHandler_Call {
+func (_c *mockOServiceHandler_RateParamsQueryHandler_Call) Run(run func(ctx context.Context, frame oscar.SNACFrame)) *mockOServiceHandler_RateParamsQueryHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context))
+		run(args[0].(context.Context), args[1].(oscar.SNACFrame))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -148,7 +150,7 @@ func (_c *mockOServiceHandler_RateParamsQueryHandler_Call) Return(_a0 oscar.SNAC
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockOServiceHandler_RateParamsQueryHandler_Call) RunAndReturn(run func(context.Context) oscar.SNACMessage) *mockOServiceHandler_RateParamsQueryHandler_Call {
+func (_c *mockOServiceHandler_RateParamsQueryHandler_Call) RunAndReturn(run func(context.Context, oscar.SNACFrame) oscar.SNACMessage) *mockOServiceHandler_RateParamsQueryHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
@@ -187,23 +189,23 @@ func (_c *mockOServiceHandler_RateParamsSubAddHandler_Call) RunAndReturn(run fun
 	return _c
 	return _c
 }
 }
 
 
-// SetUserInfoFieldsHandler provides a mock function with given fields: ctx, sess, snacPayloadIn
-func (_m *mockOServiceHandler) SetUserInfoFieldsHandler(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error) {
-	ret := _m.Called(ctx, sess, snacPayloadIn)
+// SetUserInfoFieldsHandler provides a mock function with given fields: ctx, sess, frame, bodyIn
+func (_m *mockOServiceHandler) SetUserInfoFieldsHandler(ctx context.Context, sess *state.Session, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, frame, bodyIn)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)); ok {
-		return rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)); ok {
+		return rf(ctx, sess, frame, bodyIn)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, frame, bodyIn)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) error); ok {
-		r1 = rf(ctx, sess, snacPayloadIn)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) error); ok {
+		r1 = rf(ctx, sess, frame, bodyIn)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -219,14 +221,15 @@ type mockOServiceHandler_SetUserInfoFieldsHandler_Call struct {
 // SetUserInfoFieldsHandler is a helper method to define mock.On call
 // SetUserInfoFieldsHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-//   - snacPayloadIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields
-func (_e *mockOServiceHandler_Expecter) SetUserInfoFieldsHandler(ctx interface{}, sess interface{}, snacPayloadIn interface{}) *mockOServiceHandler_SetUserInfoFieldsHandler_Call {
-	return &mockOServiceHandler_SetUserInfoFieldsHandler_Call{Call: _e.mock.On("SetUserInfoFieldsHandler", ctx, sess, snacPayloadIn)}
+//   - frame oscar.SNACFrame
+//   - bodyIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields
+func (_e *mockOServiceHandler_Expecter) SetUserInfoFieldsHandler(ctx interface{}, sess interface{}, frame interface{}, bodyIn interface{}) *mockOServiceHandler_SetUserInfoFieldsHandler_Call {
+	return &mockOServiceHandler_SetUserInfoFieldsHandler_Call{Call: _e.mock.On("SetUserInfoFieldsHandler", ctx, sess, frame, bodyIn)}
 }
 }
 
 
-func (_c *mockOServiceHandler_SetUserInfoFieldsHandler_Call) Run(run func(ctx context.Context, sess *state.Session, snacPayloadIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields)) *mockOServiceHandler_SetUserInfoFieldsHandler_Call {
+func (_c *mockOServiceHandler_SetUserInfoFieldsHandler_Call) Run(run func(ctx context.Context, sess *state.Session, frame oscar.SNACFrame, bodyIn oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields)) *mockOServiceHandler_SetUserInfoFieldsHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame), args[3].(oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -236,18 +239,18 @@ func (_c *mockOServiceHandler_SetUserInfoFieldsHandler_Call) Return(_a0 oscar.SN
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockOServiceHandler_SetUserInfoFieldsHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)) *mockOServiceHandler_SetUserInfoFieldsHandler_Call {
+func (_c *mockOServiceHandler_SetUserInfoFieldsHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame, oscar.SNAC_0x01_0x1E_OServiceSetUserInfoFields) (oscar.SNACMessage, error)) *mockOServiceHandler_SetUserInfoFieldsHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// UserInfoQueryHandler provides a mock function with given fields: ctx, sess
-func (_m *mockOServiceHandler) UserInfoQueryHandler(ctx context.Context, sess *state.Session) oscar.SNACMessage {
-	ret := _m.Called(ctx, sess)
+// UserInfoQueryHandler provides a mock function with given fields: ctx, sess, frame
+func (_m *mockOServiceHandler) UserInfoQueryHandler(ctx context.Context, sess *state.Session, frame oscar.SNACFrame) oscar.SNACMessage {
+	ret := _m.Called(ctx, sess, frame)
 
 
 	var r0 oscar.SNACMessage
 	var r0 oscar.SNACMessage
-	if rf, ok := ret.Get(0).(func(context.Context, *state.Session) oscar.SNACMessage); ok {
-		r0 = rf(ctx, sess)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, oscar.SNACFrame) oscar.SNACMessage); ok {
+		r0 = rf(ctx, sess, frame)
 	} else {
 	} else {
 		r0 = ret.Get(0).(oscar.SNACMessage)
 		r0 = ret.Get(0).(oscar.SNACMessage)
 	}
 	}
@@ -263,13 +266,14 @@ type mockOServiceHandler_UserInfoQueryHandler_Call struct {
 // UserInfoQueryHandler is a helper method to define mock.On call
 // UserInfoQueryHandler is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
 //   - sess *state.Session
 //   - sess *state.Session
-func (_e *mockOServiceHandler_Expecter) UserInfoQueryHandler(ctx interface{}, sess interface{}) *mockOServiceHandler_UserInfoQueryHandler_Call {
-	return &mockOServiceHandler_UserInfoQueryHandler_Call{Call: _e.mock.On("UserInfoQueryHandler", ctx, sess)}
+//   - frame oscar.SNACFrame
+func (_e *mockOServiceHandler_Expecter) UserInfoQueryHandler(ctx interface{}, sess interface{}, frame interface{}) *mockOServiceHandler_UserInfoQueryHandler_Call {
+	return &mockOServiceHandler_UserInfoQueryHandler_Call{Call: _e.mock.On("UserInfoQueryHandler", ctx, sess, frame)}
 }
 }
 
 
-func (_c *mockOServiceHandler_UserInfoQueryHandler_Call) Run(run func(ctx context.Context, sess *state.Session)) *mockOServiceHandler_UserInfoQueryHandler_Call {
+func (_c *mockOServiceHandler_UserInfoQueryHandler_Call) Run(run func(ctx context.Context, sess *state.Session, frame oscar.SNACFrame)) *mockOServiceHandler_UserInfoQueryHandler_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(*state.Session))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(oscar.SNACFrame))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -279,7 +283,7 @@ func (_c *mockOServiceHandler_UserInfoQueryHandler_Call) Return(_a0 oscar.SNACMe
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockOServiceHandler_UserInfoQueryHandler_Call) RunAndReturn(run func(context.Context, *state.Session) oscar.SNACMessage) *mockOServiceHandler_UserInfoQueryHandler_Call {
+func (_c *mockOServiceHandler_UserInfoQueryHandler_Call) RunAndReturn(run func(context.Context, *state.Session, oscar.SNACFrame) oscar.SNACMessage) *mockOServiceHandler_UserInfoQueryHandler_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 9 - 9
server/oservice_test.go

@@ -219,19 +219,19 @@ func TestOServiceRouter_RouteOService_ForBOS(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			svc := newMockOServiceHandler(t)
 			svc := newMockOServiceHandler(t)
 			svc.EXPECT().
 			svc.EXPECT().
-				RateParamsQueryHandler(mock.Anything).
+				RateParamsQueryHandler(mock.Anything, tc.input.Frame).
 				Return(tc.output).
 				Return(tc.output).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				UserInfoQueryHandler(mock.Anything, mock.Anything).
+				UserInfoQueryHandler(mock.Anything, mock.Anything, tc.input.Frame).
 				Return(tc.output).
 				Return(tc.output).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				ClientVersionsHandler(mock.Anything, tc.input.Body).
+				ClientVersionsHandler(mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output).
 				Return(tc.output).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				SetUserInfoFieldsHandler(mock.Anything, mock.Anything, tc.input.Body).
+				SetUserInfoFieldsHandler(mock.Anything, mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output, tc.handlerErr).
 				Return(tc.output, tc.handlerErr).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
@@ -244,7 +244,7 @@ func TestOServiceRouter_RouteOService_ForBOS(t *testing.T) {
 
 
 			svcBOS := newMockOServiceBOSHandler(t)
 			svcBOS := newMockOServiceBOSHandler(t)
 			svcBOS.EXPECT().
 			svcBOS.EXPECT().
-				ServiceRequestHandler(mock.Anything, mock.Anything, tc.input.Body).
+				ServiceRequestHandler(mock.Anything, mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output, tc.handlerErr).
 				Return(tc.output, tc.handlerErr).
 				Maybe()
 				Maybe()
 			svcBOS.EXPECT().
 			svcBOS.EXPECT().
@@ -509,19 +509,19 @@ func TestOServiceRouter_RouteOService_ForChat(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			svc := newMockOServiceHandler(t)
 			svc := newMockOServiceHandler(t)
 			svc.EXPECT().
 			svc.EXPECT().
-				RateParamsQueryHandler(mock.Anything).
+				RateParamsQueryHandler(mock.Anything, tc.input.Frame).
 				Return(tc.output).
 				Return(tc.output).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				UserInfoQueryHandler(mock.Anything, mock.Anything).
+				UserInfoQueryHandler(mock.Anything, mock.Anything, tc.input.Frame).
 				Return(tc.output).
 				Return(tc.output).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				ClientVersionsHandler(mock.Anything, tc.input.Body).
+				ClientVersionsHandler(mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output).
 				Return(tc.output).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().
-				SetUserInfoFieldsHandler(mock.Anything, mock.Anything, tc.input.Body).
+				SetUserInfoFieldsHandler(mock.Anything, mock.Anything, tc.input.Frame, tc.input.Body).
 				Return(tc.output, tc.handlerErr).
 				Return(tc.output, tc.handlerErr).
 				Maybe()
 				Maybe()
 			svc.EXPECT().
 			svc.EXPECT().