]> git.r.bdr.sh - rbdr/mobius/blame - hotline/field.go
Adopt more fixed size array types for struct fields
[rbdr/mobius] / hotline / field.go
CommitLineData
6988a057
JH
1package hotline
2
3import (
4 "encoding/binary"
95159e55 5 "io"
9c44621e 6 "slices"
6988a057
JH
7)
8
d005ef04
JH
9// List of Hotline protocol field types taken from the official 1.9 protocol document
10const (
11 FieldError = 100
12 FieldData = 101
13 FieldUserName = 102
14 FieldUserID = 103
15 FieldUserIconID = 104
16 FieldUserLogin = 105
17 FieldUserPassword = 106
18 FieldRefNum = 107
19 FieldTransferSize = 108
20 FieldChatOptions = 109
21 FieldUserAccess = 110
22 FieldUserAlias = 111 // TODO: implement
23 FieldUserFlags = 112
24 FieldOptions = 113
25 FieldChatID = 114
26 FieldChatSubject = 115
27 FieldWaitingCount = 116
28 FieldBannerType = 152
29 FieldNoServerAgreement = 152
30 FieldVersion = 160
31 FieldCommunityBannerID = 161
32 FieldServerName = 162
33 FieldFileNameWithInfo = 200
34 FieldFileName = 201
35 FieldFilePath = 202
36 FieldFileResumeData = 203
37 FieldFileTransferOptions = 204
38 FieldFileTypeString = 205
39 FieldFileCreatorString = 206
40 FieldFileSize = 207
41 FieldFileCreateDate = 208
42 FieldFileModifyDate = 209
43 FieldFileComment = 210
44 FieldFileNewName = 211
45 FieldFileNewPath = 212
46 FieldFileType = 213
47 FieldQuotingMsg = 214
48 FieldAutomaticResponse = 215
49 FieldFolderItemCount = 220
50 FieldUsernameWithInfo = 300
51 FieldNewsArtListData = 321
52 FieldNewsCatName = 322
53 FieldNewsCatListData15 = 323
54 FieldNewsPath = 325
55 FieldNewsArtID = 326
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
67)
6988a057
JH
68
69type Field struct {
95159e55
JH
70 ID [2]byte // Type of field
71 FieldSize [2]byte // Size of the data part
72 Data []byte // Actual field content
73
74 readOffset int // Internal offset to track read progress
6988a057
JH
75}
76
77type requiredField struct {
78 ID int
79 minLen int
6988a057
JH
80}
81
82func NewField(id uint16, data []byte) Field {
a55350da
JH
83 f := Field{Data: data}
84 binary.BigEndian.PutUint16(f.ID[:], id)
85 binary.BigEndian.PutUint16(f.FieldSize[:], uint16(len(data)))
6988a057 86
a55350da 87 return f
6988a057
JH
88}
89
95159e55
JH
90// fieldScanner implements bufio.SplitFunc for parsing byte slices into complete tokens
91func fieldScanner(data []byte, _ bool) (advance int, token []byte, err error) {
92 if len(data) < minFieldLen {
93 return 0, nil, nil
94 }
95
96 // tranLen represents the length of bytes that are part of the transaction
97 neededSize := minFieldLen + int(binary.BigEndian.Uint16(data[2:4]))
98 if neededSize > len(data) {
99 return 0, nil, nil
100 }
101
102 return neededSize, data[0:neededSize], nil
103}
104
105// Read implements io.Reader for Field
106func (f *Field) Read(p []byte) (int, error) {
107 buf := slices.Concat(f.ID[:], f.FieldSize[:], f.Data)
108
109 if f.readOffset >= len(buf) {
110 return 0, io.EOF // All bytes have been read
111 }
112
113 n := copy(p, buf[f.readOffset:])
114 f.readOffset += n
115
116 return n, nil
117}
118
119// Write implements io.Writer for Field
120func (f *Field) Write(p []byte) (int, error) {
121 f.ID = [2]byte(p[0:2])
122 f.FieldSize = [2]byte(p[2:4])
123
124 i := int(binary.BigEndian.Uint16(f.FieldSize[:]))
125 f.Data = p[4 : 4+i]
126
127 return minFieldLen + i, nil
6988a057 128}
d2810ae9
JH
129
130func getField(id int, fields *[]Field) *Field {
131 for _, field := range *fields {
95159e55 132 if id == int(binary.BigEndian.Uint16(field.ID[:])) {
d2810ae9
JH
133 return &field
134 }
135 }
136 return nil
137}