]>
Commit | Line | Data |
---|---|---|
1 | package hotline | |
2 | ||
3 | import ( | |
4 | "bytes" | |
5 | "encoding/binary" | |
6 | "errors" | |
7 | "io" | |
8 | "os" | |
9 | "path/filepath" | |
10 | ) | |
11 | ||
12 | type transfer struct { | |
13 | Protocol [4]byte // "HTXF" 0x48545846 | |
14 | ReferenceNumber [4]byte // Unique ID generated for the transfer | |
15 | DataSize [4]byte // File size | |
16 | RSVD [4]byte // Not implemented in Hotline Protocol | |
17 | } | |
18 | ||
19 | var HTXF = [4]byte{0x48, 0x54, 0x58, 0x46} // (HTXF) is the only supported transfer protocol | |
20 | ||
21 | func (tf *transfer) Write(b []byte) (int, error) { | |
22 | if err := binary.Read(bytes.NewReader(b), binary.BigEndian, tf); err != nil { | |
23 | return 0, err | |
24 | } | |
25 | ||
26 | if tf.Protocol != HTXF { | |
27 | return 0, errors.New("invalid protocol") | |
28 | } | |
29 | ||
30 | return len(b), nil | |
31 | } | |
32 | ||
33 | func receiveFile(r io.Reader, targetFile, resForkFile, infoFork, counterWriter io.Writer) error { | |
34 | var ffo flattenedFileObject | |
35 | if _, err := ffo.ReadFrom(r); err != nil { | |
36 | return err | |
37 | } | |
38 | ||
39 | // Write the information fork | |
40 | _, err := io.Copy(infoFork, &ffo.FlatFileInformationFork) | |
41 | if err != nil { | |
42 | return err | |
43 | } | |
44 | ||
45 | if _, err = io.CopyN(targetFile, io.TeeReader(r, counterWriter), ffo.dataSize()); err != nil { | |
46 | return err | |
47 | } | |
48 | ||
49 | if ffo.FlatFileHeader.ForkCount == [2]byte{0, 3} { | |
50 | if err := binary.Read(r, binary.BigEndian, &ffo.FlatFileResForkHeader); err != nil { | |
51 | return err | |
52 | } | |
53 | ||
54 | if _, err = io.CopyN(resForkFile, io.TeeReader(r, counterWriter), ffo.rsrcSize()); err != nil { | |
55 | return err | |
56 | } | |
57 | } | |
58 | return nil | |
59 | } | |
60 | ||
61 | // TODO: read the banner once on startup instead of once per banner fetch | |
62 | func (s *Server) bannerDownload(w io.Writer) error { | |
63 | bannerBytes, err := os.ReadFile(filepath.Join(s.ConfigDir, s.Config.BannerFile)) | |
64 | if err != nil { | |
65 | return err | |
66 | } | |
67 | _, err = w.Write(bannerBytes) | |
68 | ||
69 | return err | |
70 | } |