v1_packet_builder.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. package icq_legacy
  2. import (
  3. "encoding/binary"
  4. "net"
  5. )
  6. // V1PacketBuilder constructs V1 protocol packets.
  7. // V1 uses the same wire format as V2, but stamps version 1 in the header.
  8. // This wraps V2PacketBuilder and patches the version field in each response.
  9. type V1PacketBuilder struct {
  10. v2 V2PacketBuilder
  11. }
  12. // NewV1PacketBuilder creates a new V1PacketBuilder instance.
  13. func NewV1PacketBuilder() *V1PacketBuilder {
  14. return &V1PacketBuilder{v2: NewV2PacketBuilder()}
  15. }
  16. // patchVersion overwrites the first 2 bytes (version field) with V1.
  17. func patchVersion(pkt []byte) []byte {
  18. if len(pkt) >= 2 {
  19. binary.LittleEndian.PutUint16(pkt[0:2], ICQLegacyVersionV1)
  20. }
  21. return pkt
  22. }
  23. func (b *V1PacketBuilder) BuildLoginReply(session *LegacySession, clientSeqNum uint16) []byte {
  24. return patchVersion(b.v2.BuildLoginReply(session, clientSeqNum))
  25. }
  26. func (b *V1PacketBuilder) BuildBadPassword(seqNum uint16, version uint16) []byte {
  27. return patchVersion(b.v2.BuildBadPassword(seqNum, version))
  28. }
  29. func (b *V1PacketBuilder) BuildAck(seqNum uint16, version uint16) []byte {
  30. return patchVersion(b.v2.BuildAck(seqNum, version))
  31. }
  32. func (b *V1PacketBuilder) BuildUserOnline(seqNum uint16, uin uint32, status uint32, ip net.IP, port uint16) []byte {
  33. return patchVersion(b.v2.BuildUserOnline(seqNum, uin, status, ip, port))
  34. }
  35. func (b *V1PacketBuilder) BuildUserOffline(seqNum uint16, uin uint32) []byte {
  36. return patchVersion(b.v2.BuildUserOffline(seqNum, uin))
  37. }
  38. func (b *V1PacketBuilder) BuildContactListDone(seqNum uint16, uin uint32) []byte {
  39. return patchVersion(b.v2.BuildContactListDone(seqNum, uin))
  40. }
  41. func (b *V1PacketBuilder) BuildMessage(seqNum uint16, fromUIN uint32, msgType uint16, message string) []byte {
  42. return patchVersion(b.v2.BuildMessage(seqNum, fromUIN, msgType, message))
  43. }
  44. func (b *V1PacketBuilder) BuildSearchResult(seqNum uint16, info *UserInfoResult, isLast bool) []byte {
  45. return patchVersion(b.v2.BuildSearchResult(seqNum, info, isLast))
  46. }
  47. func (b *V1PacketBuilder) BuildStatusUpdate(seqNum uint16, uin uint32, status uint32) []byte {
  48. return patchVersion(b.v2.BuildStatusUpdate(seqNum, uin, status))
  49. }
  50. func (b *V1PacketBuilder) BuildOfflineMsgDone(seqNum uint16) []byte {
  51. return patchVersion(b.v2.BuildOfflineMsgDone(seqNum))
  52. }
  53. // BuildDepsList returns a V1-format depslist response.
  54. // Unlike V2 which sends V3-format depslist, V1 clients expect a simpler
  55. // V1/V2-format response: VERSION(2) + COMMAND(2) + SEQ(2) + DATA
  56. func (b *V1PacketBuilder) BuildDepsList(seqNum uint16, uin uint32) []byte {
  57. // Build a minimal V1-format depslist response
  58. // The client just needs to see a successful response to proceed to CMD_LOGIN
  59. data := make([]byte, 12)
  60. // Deplist version (4 bytes)
  61. binary.LittleEndian.PutUint32(data[0:4], 1)
  62. // Count = 0 (4 bytes)
  63. binary.LittleEndian.PutUint32(data[4:8], 0)
  64. // Trailer
  65. binary.LittleEndian.PutUint16(data[8:10], 0x0002)
  66. binary.LittleEndian.PutUint16(data[10:12], 0x002a)
  67. pkt := &V2ServerPacket{
  68. Version: ICQLegacyVersionV1,
  69. Command: ICQLegacySrvUserDepsList,
  70. SeqNum: seqNum,
  71. Data: data,
  72. }
  73. return MarshalV2ServerPacket(pkt)
  74. }