Răsfoiți Sursa

issue #209 - fix ICQ reconnect loop on undeliverable offline messages

Don't store or retrieve offline message for channels other than
1 or 4. It's possible that channel 2 is valid, but I do not know
which ICQ clients send ICBM on channel 2 with the store TLV set.
Mike 2 săptămâni în urmă
părinte
comite
e0d99d4080
4 a modificat fișierele cu 160 adăugiri și 2 ștergeri
  1. 6 0
      foodgroup/icbm.go
  2. 49 0
      foodgroup/icbm_test.go
  3. 5 2
      foodgroup/icq.go
  4. 100 0
      foodgroup/icq_test.go

+ 6 - 0
foodgroup/icbm.go

@@ -125,6 +125,12 @@ func (s *ICBMService) ChannelMsgToHost(ctx context.Context, instance *state.Sess
 		if _, saveOffline := inBody.Bytes(wire.ICBMTLVStore); !saveOffline {
 			return newICBMErr(inFrame.RequestID, wire.ErrorCodeNotLoggedOn), nil
 		}
+		if inBody.ChannelID != wire.ICBMChannelIM && inBody.ChannelID != wire.ICBMChannelICQ {
+			s.logger.Info("offline ICBM flag set for unsupported channel",
+				"channel", inBody.ChannelID,
+				"client_id", instance.ClientID())
+			return newICBMErr(inFrame.RequestID, wire.ErrorCodeNotLoggedOn), nil
+		}
 		canSend, err := s.canSendOfflineMessage(ctx, inBody)
 		if err != nil {
 			return nil, err

+ 49 - 0
foodgroup/icbm_test.go

@@ -592,6 +592,55 @@ func TestICBMService_ChannelMsgToHost(t *testing.T) {
 				},
 			},
 		},
+		{
+			name:     "don't store offline message for channel with no offline representation",
+			instance: newTestInstance("11111111", sessOptUIN(11111111)),
+			mockParams: mockParams{
+				relationshipFetcherParams: relationshipFetcherParams{
+					relationshipParams: relationshipParams{
+						{
+							me:   state.NewIdentScreenName("11111111"),
+							them: state.NewIdentScreenName("22222222"),
+							result: state.Relationship{
+								User: state.NewIdentScreenName("22222222"),
+							},
+						},
+					},
+				},
+				sessionRetrieverParams: sessionRetrieverParams{
+					retrieveSessionParams{
+						{
+							screenName: state.NewIdentScreenName("22222222"),
+							result:     nil,
+						},
+					},
+				},
+			},
+			inputSNAC: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					RequestID: 1234,
+				},
+				Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
+					ChannelID:  wire.ICBMChannelRendezvous,
+					ScreenName: "22222222",
+					TLVRestBlock: wire.TLVRestBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
+						},
+					},
+				},
+			},
+			expectOutput: &wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.ICBM,
+					SubGroup:  wire.ICBMErr,
+					RequestID: 1234,
+				},
+				Body: wire.SNACError{
+					Code: wire.ErrorCodeNotLoggedOn,
+				},
+			},
+		},
 		{
 			name:     "send offline message to ICQ recipient",
 			instance: newTestInstance("11111111", sessOptUIN(11111111)),

+ 5 - 2
foodgroup/icq.go

@@ -454,8 +454,11 @@ func (s *ICQService) OfflineMsgReq(ctx context.Context, inFrame wire.SNACFrame,
 			}
 
 			if reply.MsgType == 0 {
-				return fmt.Errorf("did not find an appropriate saved message payload. channel: %d",
-					msgIn.Message.ChannelID)
+				s.logger.Info("no offline message payload for channel, skipping message",
+					"channel", msgIn.Message.ChannelID,
+					"sender", msgIn.Sender.UIN(),
+					"recipient", msgIn.Recipient)
+				continue
 			}
 
 			msgOut := wire.ICQMessageReplyEnvelope{

+ 100 - 0
foodgroup/icq_test.go

@@ -2837,6 +2837,106 @@ func TestICQService_OfflineMsgReq(t *testing.T) {
 				},
 			},
 		},
+		{
+			name:     "skip offline messages with no ICQ offline representation, deliver the rest",
+			seq:      1,
+			instance: newTestInstance("11111111", sessOptUIN(11111111)),
+			mockParams: mockParams{
+				offlineMessageManagerParams: offlineMessageManagerParams{
+					retrieveMessagesParams: retrieveMessagesParams{
+						{
+							recipIn: state.NewIdentScreenName("11111111"),
+							messagesOut: []state.OfflineMessage{
+								{
+									Sender:    state.NewIdentScreenName("22222222"),
+									Recipient: state.NewIdentScreenName("11111111"),
+									Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
+										ChannelID: wire.ICBMChannelRendezvous,
+										TLVRestBlock: wire.TLVRestBlock{
+											TLVList: wire.TLVList{
+												wire.NewTLVBE(wire.ICBMTLVData, []byte{0x00, 0x00}),
+											},
+										},
+									},
+									Sent: time.Date(2024, time.August, 1, 8, 2, 0, 0, time.UTC),
+								},
+								{
+									Sender:    state.NewIdentScreenName("22222222"),
+									Recipient: state.NewIdentScreenName("11111111"),
+									Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
+										ChannelID: wire.ICBMChannelIM,
+									},
+									Sent: time.Date(2024, time.August, 1, 8, 3, 0, 0, time.UTC),
+								},
+								{
+									Sender:    state.NewIdentScreenName("22222222"),
+									Recipient: state.NewIdentScreenName("11111111"),
+									Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
+										ChannelID: wire.ICBMChannelICQ,
+									},
+									Sent: time.Date(2024, time.August, 1, 8, 4, 0, 0, time.UTC),
+								},
+								{
+									Sender:    state.NewIdentScreenName("22222222"),
+									Recipient: state.NewIdentScreenName("11111111"),
+									Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
+										ChannelID: wire.ICBMChannelIM,
+										TLVRestBlock: wire.TLVRestBlock{
+											TLVList: wire.TLVList{
+												wire.NewTLVBE(wire.ICBMTLVAOLIMData, mustICBMFragmentList(t, "hello!")),
+											},
+										},
+									},
+									Sent: time.Date(2024, time.August, 2, 12, 5, 0, 0, time.UTC),
+								},
+							},
+						},
+					},
+				},
+				messageRelayerParams: messageRelayerParams{
+					relayToSelfParams: relayToSelfParams{
+						{
+							screenName: state.NewIdentScreenName("11111111"),
+							message: wire.SNACMessage{
+								Frame: wire.SNACFrame{
+									FoodGroup: wire.ICQ,
+									SubGroup:  wire.ICQDBReply,
+									Flags:     wire.SNACFlagsMoreToCome,
+									RequestID: 1234,
+								},
+								Body: wire.SNAC_0x15_0x02_DBReply{
+									TLVRestBlock: wire.TLVRestBlock{
+										TLVList: wire.TLVList{
+											wire.NewTLVBE(wire.ICQTLVTagsMetadata, wire.ICQMessageReplyEnvelope{
+												Message: wire.ICQ_0x0041_DBQueryOfflineMsgReply{
+													ICQMetadata: wire.ICQMetadata{
+														UIN:     11111111,
+														ReqType: wire.ICQDBQueryOfflineMsgReply,
+														Seq:     1,
+													},
+													SenderUIN: 22222222,
+													Year:      uint16(2024),
+													Month:     uint8(8),
+													Day:       uint8(2),
+													Hour:      uint8(12),
+													Minute:    uint8(5),
+													MsgType:   wire.ICBMExtendedMsgTypePlain,
+													Message:   "hello!",
+												},
+											}),
+										},
+									},
+								},
+							},
+						},
+						{
+							screenName: state.NewIdentScreenName("11111111"),
+							message:    offlineMsgReplyLast(11111111, 1, 1234),
+						},
+					},
+				},
+			},
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {