9 // List of Hotline protocol field types taken from the official 1.9 protocol document
17 FieldUserPassword = 106
19 FieldTransferSize = 108
20 FieldChatOptions = 109
22 FieldUserAlias = 111 // TODO: implement
26 FieldChatSubject = 115
27 FieldWaitingCount = 116
29 FieldNoServerAgreement = 152
31 FieldCommunityBannerID = 161
33 FieldFileNameWithInfo = 200
36 FieldFileResumeData = 203
37 FieldFileTransferOptions = 204
38 FieldFileTypeString = 205
39 FieldFileCreatorString = 206
41 FieldFileCreateDate = 208
42 FieldFileModifyDate = 209
43 FieldFileComment = 210
44 FieldFileNewName = 211
45 FieldFileNewPath = 212
48 FieldAutomaticResponse = 215
49 FieldFolderItemCount = 220
50 FieldUsernameWithInfo = 300
51 FieldNewsArtListData = 321
52 FieldNewsCatName = 322
53 FieldNewsCatListData15 = 323
56 FieldNewsArtDataFlav = 327
57 FieldNewsArtTitle = 328
58 FieldNewsArtPoster = 329
59 FieldNewsArtDate = 330
60 FieldNewsArtPrevArt = 331
61 FieldNewsArtNextArt = 332
62 FieldNewsArtData = 333
63 FieldNewsArtFlags = 334 // TODO: what is this used for?
64 FieldNewsArtParentArt = 335
65 FieldNewsArt1stChildArt = 336
66 FieldNewsArtRecurseDel = 337 // TODO: implement news article recusive deletion
70 ID [2]byte // Type of field
71 FieldSize [2]byte // Size of the data part
72 Data []byte // Actual field content
74 readOffset int // Internal offset to track read progress
77 type requiredField struct {
82 func NewField(id uint16, data []byte) Field {
83 idBytes := make([]byte, 2)
84 binary.BigEndian.PutUint16(idBytes, id)
87 binary.BigEndian.PutUint16(bs, uint16(len(data)))
91 FieldSize: [2]byte(bs),
96 // fieldScanner implements bufio.SplitFunc for parsing byte slices into complete tokens
97 func fieldScanner(data []byte, _ bool) (advance int, token []byte, err error) {
98 if len(data) < minFieldLen {
102 // tranLen represents the length of bytes that are part of the transaction
103 neededSize := minFieldLen + int(binary.BigEndian.Uint16(data[2:4]))
104 if neededSize > len(data) {
108 return neededSize, data[0:neededSize], nil
111 // Read implements io.Reader for Field
112 func (f *Field) Read(p []byte) (int, error) {
113 buf := slices.Concat(f.ID[:], f.FieldSize[:], f.Data)
115 if f.readOffset >= len(buf) {
116 return 0, io.EOF // All bytes have been read
119 n := copy(p, buf[f.readOffset:])
125 // Write implements io.Writer for Field
126 func (f *Field) Write(p []byte) (int, error) {
127 f.ID = [2]byte(p[0:2])
128 f.FieldSize = [2]byte(p[2:4])
130 i := int(binary.BigEndian.Uint16(f.FieldSize[:]))
133 return minFieldLen + i, nil
136 func getField(id int, fields *[]Field) *Field {
137 for _, field := range *fields {
138 if id == int(binary.BigEndian.Uint16(field.ID[:])) {