Mike 3 месяцев назад
Родитель
Сommit
ef26496914
4 измененных файлов с 53 добавлено и 86 удалено
  1. 11 6
      foodgroup/icq.go
  2. 0 5
      server/icq_legacy/handler.go
  3. 41 75
      server/icq_legacy/service.go
  4. 1 0
      server/icq_legacy/session.go

+ 11 - 6
foodgroup/icq.go

@@ -436,13 +436,18 @@ func (s *ICQService) OfflineMsgReq(ctx context.Context, instance *state.SessionI
 				if err := wire.UnmarshalLE(&msg, buf); err != nil {
 					return err
 				}
-				if instance.Session().UsesFeedbag() {
-					// send auth grant/deny/request SNACs instead of the legacy MSG_TYPE_*
-					// ICQ messages.
-					if err := s.forwardICQAuthEvents(ctx, msgIn.Sender, msgIn.Recipient, msg); err != nil {
-						return fmt.Errorf("s.forwardICQAuthEvents: %w", err)
+				if msg.MessageType == wire.ICBMMsgTypeAuthReq ||
+					msg.MessageType == wire.ICBMMsgTypeAuthDeny ||
+					msg.MessageType == wire.ICBMMsgTypeAuthOK ||
+					msg.MessageType == wire.ICBMMsgTypeAdded {
+					if instance.Session().UsesFeedbag() {
+						// send auth grant/deny/request SNACs instead of the legacy MSG_TYPE_*
+						// ICQ messages.
+						if err := s.forwardICQAuthEvents(ctx, msgIn.Sender, msgIn.Recipient, msg); err != nil {
+							return fmt.Errorf("s.forwardICQAuthEvents: %w", err)
+						}
+						continue // do not send these messages in response
 					}
-					continue // do not send these messages in response
 				}
 				reply.MsgType = msg.MessageType
 				reply.Flags = msg.Flags

+ 0 - 5
server/icq_legacy/handler.go

@@ -307,11 +307,6 @@ type LegacyService interface {
 
 	// AckOfflineMessages acknowledges and deletes offline messages for the given UIN.
 	AckOfflineMessages(ctx context.Context, uin uint32) error
-	// SaveOfflineMessage stores a message for offline delivery when the target user is not online.
-	// This is called by V3/V5 handlers when a message is sent to an offline user.
-	// From iserverd v3_process_sysmsg() and v5_process_sysmsg() - when target is offline,
-	// the message is stored in the database for later delivery.
-	SaveOfflineMessage(ctx context.Context, fromUIN, toUIN uint32, msgType uint16, message string) error
 
 	// ProcessMessage handles message routing and offline storage.
 	// This is the service layer method for messaging that handlers call after

+ 41 - 75
server/icq_legacy/service.go

@@ -485,65 +485,57 @@ func (s *ICQLegacyService) ProcessMessage(ctx context.Context, session *LegacySe
 
 	// Check if target user is online via OSCAR session
 	toScreenName := state.NewIdentScreenName(strconv.FormatUint(uint64(req.ToUIN), 10))
-	oscarSession := s.sessionRetriever.RetrieveSession(toScreenName)
-	if oscarSession != nil {
-		// Target is online via OSCAR protocol
-		result.TargetOnline = true
-		result.Delivered = true
-		result.TargetVersion = 0 // OSCAR client, not legacy
+	// Target is online via OSCAR protocol
+	result.TargetOnline = true
+	result.Delivered = true
+	result.TargetVersion = 0 // OSCAR client, not legacy
 
-		s.logger.Debug("ProcessMessage: target online (OSCAR)",
-			"to", req.ToUIN,
-		)
+	s.logger.Debug("ProcessMessage: target online (OSCAR)",
+		"to", req.ToUIN,
+	)
 
-		// Send message to OSCAR client
-		fromScreenName := state.NewIdentScreenName(strconv.FormatUint(uint64(req.FromUIN), 10))
+	// Send message to OSCAR client
+	fromScreenName := state.NewIdentScreenName(strconv.FormatUint(uint64(req.FromUIN), 10))
 
-		frame := wire.SNACFrame{
-			FoodGroup: wire.ICBM,
-			SubGroup:  wire.ICBMChannelMsgToHost,
-		}
-		snac := wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
-			ChannelID:  wire.ICBMChannelICQ,
-			ScreenName: toScreenName.String(),
-			TLVRestBlock: wire.TLVRestBlock{
-				TLVList: wire.TLVList{
-					wire.NewTLVLE(wire.ICBMTLVData, wire.ICBMCh4Message{
-						UIN:         fromScreenName.UIN(),
-						MessageType: uint8(req.MsgType),
-						Message:     req.Message,
-					}),
-					wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
-				},
+	frame := wire.SNACFrame{
+		FoodGroup: wire.ICBM,
+		SubGroup:  wire.ICBMChannelMsgToHost,
+	}
+	snac := wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
+		ChannelID:  wire.ICBMChannelICQ,
+		ScreenName: toScreenName.String(),
+		TLVRestBlock: wire.TLVRestBlock{
+			TLVList: wire.TLVList{
+				wire.NewTLVLE(wire.ICBMTLVData, wire.ICBMCh4Message{
+					UIN:         fromScreenName.UIN(),
+					MessageType: uint8(req.MsgType),
+					Message:     req.Message,
+				}),
+				wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
 			},
-		}
-		if _, err := s.icbmService.ChannelMsgToHost(ctx, session.Instance, frame, snac); err != nil {
-			s.logger.Error("ProcessMessage: failed to send to OSCAR client",
-				"to", req.ToUIN,
-				"err", err,
-			)
-			// Still mark as delivered since we attempted
-		}
-		return result, nil
+		},
 	}
-
-	// Target is offline - store message for later delivery
-	fromScreenName := state.NewIdentScreenName(strconv.FormatUint(uint64(req.FromUIN), 10))
-	if err := s.storeOfflineMessage(ctx, fromScreenName, toScreenName, req.MsgType, req.Message); err != nil {
-		s.logger.Error("ProcessMessage: failed to store offline message",
-			"from", req.FromUIN,
+	resp, err := s.icbmService.ChannelMsgToHost(ctx, session.Instance, frame, snac)
+	if err != nil {
+		s.logger.Error("ProcessMessage: failed to send to OSCAR client",
 			"to", req.ToUIN,
 			"err", err,
 		)
-		return result, fmt.Errorf("storing offline message: %w", err)
+		// Still mark as delivered since we attempted
 	}
 
-	result.StoredOffline = true
-	s.logger.Info("ProcessMessage: message stored for offline delivery",
-		"from", req.FromUIN,
-		"to", req.ToUIN,
-		"type", fmt.Sprintf("0x%04X", req.MsgType),
-	)
+	if resp != nil && resp.Frame.FoodGroup == wire.ICBM && resp.Frame.SubGroup == wire.ICBMErr {
+		if snErr, ok := resp.Body.(wire.SNACError); ok {
+			if snErr.Code == wire.ErrorCodeNotLoggedOn {
+				result.StoredOffline = true
+				s.logger.Info("ProcessMessage: message stored for offline delivery",
+					"from", req.FromUIN,
+					"to", req.ToUIN,
+					"type", fmt.Sprintf("0x%04X", req.MsgType),
+				)
+			}
+		}
+	}
 
 	return result, nil
 }
@@ -829,32 +821,6 @@ func (s *ICQLegacyService) sendToOSCARClient(ctx context.Context, from, to state
 	return nil
 }
 
-// SaveOfflineMessage stores a message for offline delivery when the target user is not online.
-// This is the public interface called by V3/V5 handlers when a message is sent to an offline user.
-// From iserverd v3_process_sysmsg() and v5_process_sysmsg() - when target is offline,
-// the message is stored in the database for later delivery.
-//
-// Parameters:
-//   - fromUIN: The sender's UIN
-//   - toUIN: The recipient's UIN (who is offline)
-//   - msgType: The ICQ message type (e.g., 0x0001 for text, 0x0004 for URL)
-//   - message: The message content
-//
-// Returns nil on success, or an error if the message could not be stored.
-func (s *ICQLegacyService) SaveOfflineMessage(ctx context.Context, fromUIN, toUIN uint32, msgType uint16, message string) error {
-	fromScreenName := state.NewIdentScreenName(strconv.FormatUint(uint64(fromUIN), 10))
-	toScreenName := state.NewIdentScreenName(strconv.FormatUint(uint64(toUIN), 10))
-
-	s.logger.Debug("storing offline message",
-		"from", fromUIN,
-		"to", toUIN,
-		"type", fmt.Sprintf("0x%04X", msgType),
-		"msg_len", len(message),
-	)
-
-	return s.storeOfflineMessage(ctx, fromScreenName, toScreenName, msgType, message)
-}
-
 // storeOfflineMessage stores a message for offline delivery
 func (s *ICQLegacyService) storeOfflineMessage(ctx context.Context, from, to state.IdentScreenName, msgType uint16, message string) error {
 	// Create ICBM fragment list for the message

+ 1 - 0
server/icq_legacy/session.go

@@ -94,6 +94,7 @@ func (m *LegacySessionManager) CreateSession(uin uint32, addr *net.UDPAddr, vers
 	// session's TLVUserInfo() include the ICQ flag and DC info TLV that
 	// ICQ 2003b requires to display the user as online.
 	instance.SetUserInfoFlag(wire.OServiceUserFlagICQ | wire.OServiceUserFlagOSCARFree)
+	instance.Session().SetUIN(uin)
 
 	session := &LegacySession{
 		UIN:          uin,