Skip to content

Commit

Permalink
issue #48 - fix chat in pidgin client
Browse files Browse the repository at this point in the history
This commit implements the following changes that makes Pidgin chat
work:

- chat detail level value must be "2"
- set TLV 0xDA in chat room info
- change the chat cookie to this format: %s-%s-%s, where the third %s is
  the chat room name.

Co-authored-by: Josh Knight <josh@noobbox.com>
  • Loading branch information
mk6i and jgknight committed Jul 13, 2024
1 parent 966f115 commit 060698f
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 33 deletions.
2 changes: 1 addition & 1 deletion foodgroup/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func sendChatRoomInfoUpdate(ctx context.Context, sess *state.Session, chatMessag
Exchange: room.Exchange,
Cookie: room.Cookie,
InstanceNumber: room.InstanceNumber,
DetailLevel: room.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: room.TLVList(),
},
Expand Down
16 changes: 13 additions & 3 deletions foodgroup/chat_nav.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ var (
errChatNavMismatchedExchange = errors.New("chat room exchange does not match requested exchange")
)

// detailLevel is the detail level of the chat room (whatever that means).
// Pidgin 2.13.0 expects value 0x02.
const detailLevel uint8 = 2

// NewChatNavService creates a new instance of NewChatNavService.
func NewChatNavService(logger *slog.Logger, chatRoomManager ChatRoomRegistry, fnNewChatRoom func() state.ChatRoom) *ChatNavService {
return &ChatNavService{
Expand Down Expand Up @@ -104,10 +108,16 @@ func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFra

room = s.fnNewChatRoom()
room.Creator = sess.IdentScreenName()
room.DetailLevel = inBody.DetailLevel
room.Exchange = inBody.Exchange
room.InstanceNumber = inBody.InstanceNumber
room.Name = name
// According to Pidgin, the chat cookie is a 3-part identifier. The
// third segment is the chat name, which is shown explicitly in the
// Pidgin code. We can assume that the first two parts were the
// exchange and instance number. As of now, Pidgin is the only client
// that cares about the cookie format, and it only cares about the chat
// name segment.
room.Cookie = fmt.Sprintf("%d-%d-%s", inBody.Exchange, inBody.InstanceNumber, name)

if err := s.chatRoomManager.CreateChatRoom(room); err != nil {
return wire.SNACMessage{}, fmt.Errorf("%w: %w", errChatNavRoomCreateFailed, err)
Expand All @@ -129,7 +139,7 @@ func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFra
Exchange: room.Exchange,
Cookie: room.Cookie,
InstanceNumber: room.InstanceNumber,
DetailLevel: room.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: room.TLVList(),
},
Expand Down Expand Up @@ -170,7 +180,7 @@ func (s ChatNavService) RequestRoomInfo(_ context.Context, inFrame wire.SNACFram
Exchange: room.Exchange,
Cookie: room.Cookie,
InstanceNumber: room.InstanceNumber,
DetailLevel: room.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: room.TLVList(),
},
Expand Down
34 changes: 14 additions & 20 deletions foodgroup/chat_nav_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ import (

func TestChatNavService_CreateRoom(t *testing.T) {
basicChatRoom := state.ChatRoom{
Cookie: "dummy-cookie",
Cookie: "4-2-the-chat-room-name",
CreateTime: time.UnixMilli(0),
Creator: state.NewIdentScreenName("the-screen-name"),
DetailLevel: 3,
Exchange: 4,
InstanceNumber: 2,
Name: "the-chat-room-name",
Expand All @@ -27,7 +26,6 @@ func TestChatNavService_CreateRoom(t *testing.T) {
Cookie: "dummy-cookie",
CreateTime: time.UnixMilli(0),
Creator: state.NewIdentScreenName("the-screen-name"),
DetailLevel: 3,
Exchange: 5,
InstanceNumber: 2,
Name: "the-public-chat-room-name",
Expand Down Expand Up @@ -55,7 +53,7 @@ func TestChatNavService_CreateRoom(t *testing.T) {
Exchange: basicChatRoom.Exchange,
Cookie: "create", // actual canned value sent by AIM client
InstanceNumber: basicChatRoom.InstanceNumber,
DetailLevel: basicChatRoom.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: wire.TLVList{
wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name),
Expand All @@ -78,7 +76,7 @@ func TestChatNavService_CreateRoom(t *testing.T) {
Exchange: basicChatRoom.Exchange,
Cookie: basicChatRoom.Cookie,
InstanceNumber: basicChatRoom.InstanceNumber,
DetailLevel: basicChatRoom.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: basicChatRoom.TLVList(),
},
Expand Down Expand Up @@ -112,7 +110,7 @@ func TestChatNavService_CreateRoom(t *testing.T) {
Exchange: basicChatRoom.Exchange,
Cookie: "create", // actual canned value sent by AIM client
InstanceNumber: basicChatRoom.InstanceNumber,
DetailLevel: basicChatRoom.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: wire.TLVList{
wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name),
Expand All @@ -135,7 +133,7 @@ func TestChatNavService_CreateRoom(t *testing.T) {
Exchange: basicChatRoom.Exchange,
Cookie: basicChatRoom.Cookie,
InstanceNumber: basicChatRoom.InstanceNumber,
DetailLevel: basicChatRoom.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: basicChatRoom.TLVList(),
},
Expand Down Expand Up @@ -177,7 +175,7 @@ func TestChatNavService_CreateRoom(t *testing.T) {
Exchange: publicChatRoom.Exchange,
Cookie: "create", // actual canned value sent by AIM client
InstanceNumber: publicChatRoom.InstanceNumber,
DetailLevel: publicChatRoom.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: wire.TLVList{
wire.NewTLV(wire.ChatRoomTLVRoomName, publicChatRoom.Name),
Expand All @@ -200,7 +198,7 @@ func TestChatNavService_CreateRoom(t *testing.T) {
Exchange: publicChatRoom.Exchange,
Cookie: publicChatRoom.Cookie,
InstanceNumber: publicChatRoom.InstanceNumber,
DetailLevel: publicChatRoom.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: publicChatRoom.TLVList(),
},
Expand Down Expand Up @@ -234,7 +232,7 @@ func TestChatNavService_CreateRoom(t *testing.T) {
Exchange: publicChatRoom.Exchange,
Cookie: "create", // actual canned value sent by AIM client
InstanceNumber: publicChatRoom.InstanceNumber,
DetailLevel: publicChatRoom.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: wire.TLVList{
wire.NewTLV(wire.ChatRoomTLVRoomName, publicChatRoom.Name),
Expand Down Expand Up @@ -279,7 +277,7 @@ func TestChatNavService_CreateRoom(t *testing.T) {
Exchange: 1337,
Cookie: "create", // actual canned value sent by AIM client
InstanceNumber: basicChatRoom.InstanceNumber,
DetailLevel: basicChatRoom.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: wire.TLVList{
wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name),
Expand Down Expand Up @@ -310,7 +308,7 @@ func TestChatNavService_CreateRoom(t *testing.T) {
Exchange: basicChatRoom.Exchange,
Cookie: "create", // actual canned value sent by AIM client
InstanceNumber: basicChatRoom.InstanceNumber,
DetailLevel: basicChatRoom.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: wire.TLVList{}, // intentionally empty for test
},
Expand All @@ -331,7 +329,7 @@ func TestChatNavService_CreateRoom(t *testing.T) {
Exchange: basicChatRoom.Exchange,
Cookie: "create", // actual canned value sent by AIM client
InstanceNumber: basicChatRoom.InstanceNumber,
DetailLevel: basicChatRoom.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: wire.TLVList{
wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name),
Expand Down Expand Up @@ -374,7 +372,7 @@ func TestChatNavService_CreateRoom(t *testing.T) {
Exchange: basicChatRoom.Exchange,
Cookie: "create", // actual canned value sent by AIM client
InstanceNumber: basicChatRoom.InstanceNumber,
DetailLevel: basicChatRoom.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: wire.TLVList{
wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name),
Expand Down Expand Up @@ -453,7 +451,7 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) {
TLVList: wire.TLVList{
wire.NewTLV(0x04, wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
Cookie: "the-chat-cookie",
DetailLevel: 2,
DetailLevel: detailLevel,
Exchange: state.PrivateExchange,
InstanceNumber: 8,
TLVBlock: wire.TLVBlock{
Expand All @@ -471,7 +469,6 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) {
cookie: "the-chat-cookie",
room: state.ChatRoom{
Cookie: "the-chat-cookie",
DetailLevel: 2,
Exchange: state.PrivateExchange,
InstanceNumber: 8,
},
Expand Down Expand Up @@ -502,7 +499,7 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) {
TLVList: wire.TLVList{
wire.NewTLV(0x04, wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
Cookie: "the-chat-cookie",
DetailLevel: 2,
DetailLevel: detailLevel,
Exchange: state.PublicExchange,
InstanceNumber: 8,
TLVBlock: wire.TLVBlock{
Expand All @@ -520,7 +517,6 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) {
cookie: "the-chat-cookie",
room: state.ChatRoom{
Cookie: "the-chat-cookie",
DetailLevel: 2,
Exchange: state.PublicExchange,
InstanceNumber: 8,
},
Expand Down Expand Up @@ -571,7 +567,6 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) {
cookie: "the-chat-cookie",
room: state.ChatRoom{
Cookie: "the-chat-cookie",
DetailLevel: 2,
Exchange: state.PublicExchange,
InstanceNumber: 8,
},
Expand Down Expand Up @@ -600,7 +595,6 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) {
cookie: "the-chat-cookie",
room: state.ChatRoom{
Cookie: "the-chat-cookie",
DetailLevel: 2,
Exchange: state.PrivateExchange,
InstanceNumber: 8,
},
Expand Down
5 changes: 1 addition & 4 deletions foodgroup/oservice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ func TestOServiceServiceForBOS_ServiceRequest(t *testing.T) {
cookie: "the-chat-cookie",
room: state.ChatRoom{
CreateTime: time.UnixMilli(0),
DetailLevel: 4,
Exchange: 8,
Cookie: "the-chat-cookie",
InstanceNumber: 16,
Expand Down Expand Up @@ -1706,7 +1705,6 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) {
chatter2 := newTestSession("chatter-2", sessOptChatRoomCookie("the-cookie"))
chatRoom := state.ChatRoom{
Cookie: "the-cookie",
DetailLevel: 1,
Exchange: 2,
InstanceNumber: 3,
Name: "the-chat-room",
Expand Down Expand Up @@ -1770,7 +1768,7 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) {
Exchange: chatRoom.Exchange,
Cookie: chatRoom.Cookie,
InstanceNumber: chatRoom.InstanceNumber,
DetailLevel: chatRoom.DetailLevel,
DetailLevel: detailLevel,
TLVBlock: wire.TLVBlock{
TLVList: chatRoom.TLVList(),
},
Expand Down Expand Up @@ -1801,7 +1799,6 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) {
cookie: "the-cookie",
room: state.ChatRoom{
Cookie: "the-cookie",
DetailLevel: 1,
Exchange: 2,
InstanceNumber: 3,
Name: "the-chat-room",
Expand Down
6 changes: 1 addition & 5 deletions state/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
"time"

"github.com/mk6i/retro-aim-server/wire"

"github.com/google/uuid"
)

const (
Expand All @@ -34,8 +32,6 @@ type ChatRoom struct {
CreateTime time.Time
// Creator is the screen name of the user who created the chat room.
Creator IdentScreenName
// DetailLevel is the detail level of the chat room. Unclear what this value means.
DetailLevel uint8
// Exchange indicates which exchange the chatroom belongs to. Typically, a canned value.
Exchange uint16
// InstanceNumber indicates which instance chatroom exists in. Typically, a canned value.
Expand Down Expand Up @@ -79,13 +75,13 @@ func (c ChatRoom) TLVList() []wire.TLV {
wire.NewTLV(wire.ChatRoomTLVNavCreatePerms, uint8(2)),
wire.NewTLV(wire.ChatRoomTLVFullyQualifiedName, c.Name),
wire.NewTLV(wire.ChatRoomTLVRoomName, c.Name),
wire.NewTLV(wire.ChatRoomTLVMaxMsgVisLen, uint16(1024)),
}
}

// NewChatRoom creates new state.ChatRoom objects
func NewChatRoom() ChatRoom {
return ChatRoom{
Cookie: uuid.New().String(),
CreateTime: time.Now().UTC(),
}
}
1 change: 1 addition & 0 deletions state/chat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func TestChatRoom_TLVList(t *testing.T) {
wire.NewTLV(wire.ChatRoomTLVNavCreatePerms, uint8(2)),
wire.NewTLV(wire.ChatRoomTLVFullyQualifiedName, room.Name),
wire.NewTLV(wire.ChatRoomTLVRoomName, room.Name),
wire.NewTLV(wire.ChatRoomTLVMaxMsgVisLen, uint16(1024)),
}

assert.Equal(t, want, have)
Expand Down
1 change: 1 addition & 0 deletions wire/snacs.go
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,7 @@ const (
ChatRoomTLVLang1 uint16 = 0xD7
ChatRoomTLVCharSet2 uint16 = 0xD8
ChatRoomTLVLang2 uint16 = 0xD9
ChatRoomTLVMaxMsgVisLen uint16 = 0xDA
)

type SNAC_0x0E_0x02_ChatRoomInfoUpdate struct {
Expand Down

0 comments on commit 060698f

Please sign in to comment.